Fixed issue #27.

Change-Id: I8332bd16db791483c41b614f508b49b2b092a257
diff --git a/core/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java b/core/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
index d69dabd..a93dbc2 100644
--- a/core/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
+++ b/core/src/main/java/de/ids_mannheim/korap/exceptions/StatusCodes.java
@@ -13,7 +13,7 @@
     /**
      * 100 status codes for standard system errors
      */
-    public static final int DEFAULT_ERROR = 100;
+    public static final int GENERAL_ERROR = 100;
     public static final int NO_RESULT_FOUND = 101;
     public static final int UNSUPPORTED_AUTHENTICATION_SCHEME = 102;
     public static final int UNSUPPORTED_OPERATION = 103;
@@ -24,6 +24,7 @@
     public static final int NOT_SUPPORTED = 108;
     public static final int NOT_ALLOWED = 109;
     public static final int HTTPS_REQUIRED = 110;
+    public static final int INVALID_ALGORITHM = 111;
 
     /**
      * 200 status codes general JSON serialization error
diff --git a/full/src/main/java/de/ids_mannheim/korap/config/FullConfiguration.java b/full/src/main/java/de/ids_mannheim/korap/config/FullConfiguration.java
index b11f8cf..fc86217 100644
--- a/full/src/main/java/de/ids_mannheim/korap/config/FullConfiguration.java
+++ b/full/src/main/java/de/ids_mannheim/korap/config/FullConfiguration.java
@@ -66,7 +66,9 @@
     private boolean isSoftDeleteGroup;
     private boolean isSoftDeleteGroupMember;
 
-    private EncryptionIface.Encryption encryption;
+    private EncryptionIface.Encryption secureHashAlgorithm;
+    private String secureRandomAlgorithm;
+    private String messageDigestAlgorithm;
 
     private AuthenticationMethod OAuth2passwordAuthentication;
     private String nativeClientHost;
@@ -103,14 +105,24 @@
         setMailConfiguration(properties);
         ldapConfig = properties.getProperty("ldap.config");
 
-        setEncryption(Enum.valueOf(EncryptionIface.Encryption.class,
-                properties.getProperty("security.encryption", "BCRYPT")));
-
+        setSecurityConfiguration(properties);
         setOAuth2Configuration(properties);
         setOpenIdConfiguration(properties);
         setRSAKeys(properties);
     }
 
+    private void setSecurityConfiguration (Properties properties) {
+        setSecureHashAlgorithm(Enum.valueOf(EncryptionIface.Encryption.class,
+                properties.getProperty("security.secure.hash.algorithm",
+                        "BCRYPT")));
+
+        setSecureRandomAlgorithm(properties
+                .getProperty("security.secure.random.algorithm", "SHA1PRNG"));
+
+        setMessageDigestAlgorithm(
+                properties.getProperty("security.md.algorithm", "MD5"));
+    }
+
     private void setOpenIdConfiguration (Properties properties)
             throws URISyntaxException, MalformedURLException {
         String issuerStr = properties.getProperty("security.jwt.issuer",
@@ -466,12 +478,13 @@
         this.emailAddressRetrieval = emailAddressRetrieval;
     }
 
-    public EncryptionIface.Encryption getEncryption () {
-        return encryption;
+    public EncryptionIface.Encryption getSecureHashAlgorithm () {
+        return secureHashAlgorithm;
     }
 
-    public void setEncryption (EncryptionIface.Encryption encryption) {
-        this.encryption = encryption;
+    public void setSecureHashAlgorithm (
+            EncryptionIface.Encryption secureHashAlgorithm) {
+        this.secureHashAlgorithm = secureHashAlgorithm;
     }
 
     public AuthenticationMethod getOAuth2passwordAuthentication () {
@@ -619,4 +632,20 @@
     public void setAuthorizationCodeExpiry (int authorizationCodeExpiry) {
         this.authorizationCodeExpiry = authorizationCodeExpiry;
     }
+
+    public String getSecureRandomAlgorithm () {
+        return secureRandomAlgorithm;
+    }
+
+    public void setSecureRandomAlgorithm (String secureRandomAlgorithm) {
+        this.secureRandomAlgorithm = secureRandomAlgorithm;
+    }
+
+    public String getMessageDigestAlgorithm () {
+        return messageDigestAlgorithm;
+    }
+
+    public void setMessageDigestAlgorithm (String messageDigestAlgorithm) {
+        this.messageDigestAlgorithm = messageDigestAlgorithm;
+    }
 }
diff --git a/full/src/main/java/de/ids_mannheim/korap/encryption/KustvaktEncryption.java b/full/src/main/java/de/ids_mannheim/korap/encryption/KustvaktEncryption.java
index 735546c..211e6e5 100644
--- a/full/src/main/java/de/ids_mannheim/korap/encryption/KustvaktEncryption.java
+++ b/full/src/main/java/de/ids_mannheim/korap/encryption/KustvaktEncryption.java
@@ -63,7 +63,7 @@
     @Override
     public String secureHash (String input, String salt) {
         String hashString = "";
-        switch (config.getEncryption()) {
+        switch (config.getSecureHashAlgorithm()) {
             case ESAPICYPHER:
                 break;
             case SIMPLE:
@@ -83,7 +83,7 @@
                 hashString = bcryptHash(input, salt);
                 break;
             default:
-                jlog.warn("Invalid value: "+ config.getEncryption());
+                jlog.warn("Invalid value: "+ config.getSecureHashAlgorithm());
                 break;
         }
         return hashString;
@@ -191,7 +191,7 @@
     @Override
     public boolean checkHash (String plain, String hash, String salt) {
         String pw = "";
-        switch (config.getEncryption()) {
+        switch (config.getSecureHashAlgorithm()) {
             case ESAPICYPHER:
                 pw = secureHash(plain, salt);
                 break;
@@ -212,7 +212,7 @@
 
     @Override
     public boolean checkHash (String plain, String hash) {
-        switch (config.getEncryption()) {
+        switch (config.getSecureHashAlgorithm()) {
             case ESAPICYPHER:
                 return secureHash(plain).equals(hash);
             case BCRYPT:
diff --git a/full/src/main/java/de/ids_mannheim/korap/encryption/RandomCodeGenerator.java b/full/src/main/java/de/ids_mannheim/korap/encryption/RandomCodeGenerator.java
new file mode 100644
index 0000000..e6b60ae
--- /dev/null
+++ b/full/src/main/java/de/ids_mannheim/korap/encryption/RandomCodeGenerator.java
@@ -0,0 +1,64 @@
+package de.ids_mannheim.korap.encryption;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+import java.security.SecureRandom;
+import java.util.UUID;
+
+import javax.annotation.PostConstruct;
+
+import org.apache.commons.codec.binary.Base64;
+import org.apache.commons.lang.ArrayUtils;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.stereotype.Component;
+
+import de.ids_mannheim.korap.config.FullConfiguration;
+import de.ids_mannheim.korap.exceptions.KustvaktException;
+import de.ids_mannheim.korap.exceptions.StatusCodes;
+
+/**
+ * Generates a random string that can be used for tokens, client id,
+ * client secret, etc.
+ * 
+ * @author margaretha
+ *
+ */
+@Component
+public class RandomCodeGenerator {
+
+    @Autowired
+    private FullConfiguration config;
+
+    public static SecureRandom secureRandom;
+
+    @PostConstruct
+    public void init () throws NoSuchAlgorithmException {
+        secureRandom =
+                SecureRandom.getInstance(config.getSecureRandomAlgorithm());
+    }
+
+    public String createRandomCode () throws KustvaktException {
+        UUID randomUUID = UUID.randomUUID();
+        byte[] uuidBytes = randomUUID.toString().getBytes();
+        byte[] secureBytes = new byte[3];
+        secureRandom.nextBytes(secureBytes);
+
+        byte[] bytes = ArrayUtils.addAll(uuidBytes, secureBytes);
+
+        try {
+            MessageDigest md = MessageDigest
+                    .getInstance(config.getMessageDigestAlgorithm());
+            md.update(bytes);
+            byte[] digest = md.digest();
+            String code = Base64.encodeBase64String(digest);
+            md.reset();
+            return code;
+        }
+        catch (NoSuchAlgorithmException e) {
+            throw new KustvaktException(StatusCodes.INVALID_ALGORITHM,
+                    config.getMessageDigestAlgorithm()
+                            + "is not a valid MessageDigest algorithm");
+        }
+    }
+
+}
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuAuthorizationService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuAuthorizationService.java
index b05ed06..cff1ce2 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuAuthorizationService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuAuthorizationService.java
@@ -1,13 +1,13 @@
 package de.ids_mannheim.korap.oauth2.oltu.service;
 
+import java.io.UnsupportedEncodingException;
 import java.net.URI;
 import java.net.URISyntaxException;
+import java.net.URLEncoder;
 import java.time.ZonedDateTime;
 
 import javax.servlet.http.HttpServletRequest;
 
-import org.apache.commons.codec.binary.Base64;
-import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
 import org.apache.oltu.oauth2.as.request.OAuthAuthzRequest;
 import org.apache.oltu.oauth2.as.response.OAuthASResponse;
 import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
@@ -17,6 +17,7 @@
 
 import com.sun.jersey.api.client.ClientResponse.Status;
 
+import de.ids_mannheim.korap.encryption.RandomCodeGenerator;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.oauth2.constant.OAuth2Error;
@@ -33,7 +34,7 @@
 public class OltuAuthorizationService extends OAuth2AuthorizationService {
 
     @Autowired
-    private OAuthIssuer oauthIssuer;
+    private RandomCodeGenerator codeGenerator;
 
     /**
      * Authorization code request does not require client
@@ -57,8 +58,8 @@
         String clientId = authzRequest.getClientId();
         OAuth2Client client = clientService.authenticateClientId(clientId);
 
-        String redirectUri = authzRequest.getRedirectURI();
-        String verifiedRedirectUri = verifyRedirectUri(client, redirectUri);
+        String redirectUriStr = authzRequest.getRedirectURI();
+        String verifiedRedirectUri = verifyRedirectUri(client, redirectUriStr);
 
         URI redirectURI;
         try {
@@ -72,18 +73,21 @@
         String scope, code;
         try {
             checkResponseType(authzRequest.getResponseType());
-
-            code = oauthIssuer.authorizationCode();
-//            code = Base64.encodeBase64String(code.getBytes());
-            
+            code = URLEncoder.encode(codeGenerator.createRandomCode(), "UTF-8");
             scope = createAuthorization(username, authzRequest.getClientId(),
-                    redirectUri, authzRequest.getScopes(), code,
+                    redirectUriStr, authzRequest.getScopes(), code,
                     authenticationTime, null);
         }
         catch (KustvaktException e) {
             e.setRedirectUri(redirectURI);
             throw e;
         }
+        catch (UnsupportedEncodingException e) {
+            KustvaktException ke = new KustvaktException(
+                    StatusCodes.GENERAL_ERROR, e.getMessage());
+            ke.setRedirectUri(redirectURI);
+            throw ke;
+        }
 
         OAuthResponse oAuthResponse;
         try {
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuTokenService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuTokenService.java
index e8ad63b..c9b574d 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuTokenService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/oltu/service/OltuTokenService.java
@@ -6,8 +6,6 @@
 
 import javax.ws.rs.core.Response.Status;
 
-import org.apache.commons.codec.binary.Base64;
-import org.apache.oltu.oauth2.as.issuer.OAuthIssuer;
 import org.apache.oltu.oauth2.as.request.AbstractOAuthTokenRequest;
 import org.apache.oltu.oauth2.as.response.OAuthASResponse;
 import org.apache.oltu.oauth2.common.exception.OAuthSystemException;
@@ -18,6 +16,7 @@
 import org.springframework.stereotype.Service;
 
 import de.ids_mannheim.korap.config.Attributes;
+import de.ids_mannheim.korap.encryption.RandomCodeGenerator;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.oauth2.constant.OAuth2Error;
@@ -30,10 +29,10 @@
 
 @Service
 public class OltuTokenService extends OAuth2TokenService {
-
+    
     @Autowired
-    private OAuthIssuer oauthIssuer;
-
+    private RandomCodeGenerator randomGenerator; 
+    
     @Autowired
     private AccessTokenDao tokenDao;
 
@@ -281,11 +280,8 @@
             ZonedDateTime authenticationTime)
             throws OAuthSystemException, KustvaktException {
 
-        String accessToken = oauthIssuer.accessToken();
-//        accessToken = Base64.encodeBase64String(accessToken.getBytes());
-
-        String refreshToken = oauthIssuer.refreshToken();
-//        refreshToken = Base64.encodeBase64String(refreshToken.getBytes());
+        String accessToken = randomGenerator.createRandomCode();
+        String refreshToken = randomGenerator.createRandomCode();
 
         tokenDao.storeAccessToken(accessToken, refreshToken, accessScopes,
                 userId, clientId, authenticationTime);
diff --git a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java
index 6d61e02..8b3a639 100644
--- a/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java
+++ b/full/src/main/java/de/ids_mannheim/korap/oauth2/service/OAuth2ClientService.java
@@ -13,6 +13,7 @@
 import de.ids_mannheim.korap.config.FullConfiguration;
 import de.ids_mannheim.korap.dao.AdminDao;
 import de.ids_mannheim.korap.dto.OAuth2ClientDto;
+import de.ids_mannheim.korap.encryption.RandomCodeGenerator;
 import de.ids_mannheim.korap.exceptions.KustvaktException;
 import de.ids_mannheim.korap.exceptions.StatusCodes;
 import de.ids_mannheim.korap.interfaces.EncryptionIface;
@@ -53,6 +54,8 @@
     @Autowired
     private EncryptionIface encryption;
     @Autowired
+    private RandomCodeGenerator codeGenerator;
+    @Autowired
     private FullConfiguration config;
 
     public OAuth2ClientDto registerClient (OAuth2ClientJson clientJson,
@@ -91,12 +94,12 @@
             // installation of a native application client on a
             // specific device.
 
-            secret = encryption.createToken();
+            secret = codeGenerator.createRandomCode();
             secretHashcode = encryption.secureHash(secret,
                     config.getPasscodeSaltField());
         }
 
-        String id = encryption.createRandomNumber();
+        String id = codeGenerator.createRandomCode();
         try {
             clientDao.registerClient(id, secretHashcode, clientJson.getName(),
                     clientJson.getType(), isNative, url, urlHashCode,
diff --git a/full/src/main/resources/kustvakt.conf b/full/src/main/resources/kustvakt.conf
index 0c21e43..22e7e14 100644
--- a/full/src/main/resources/kustvakt.conf
+++ b/full/src/main/resources/kustvakt.conf
@@ -65,7 +65,16 @@
 security.tokenTTL=72H
 security.shortTokenTTL=45M
 
-## specifies the user data field that is used to salt user passwords
+## see SecureRandom Number Generation Algorithms
+## default SHA1PRNG
+security.secure.random.algorithm=SHA1PRNG
+
+## see MessageDigest Algorithms
+## default MD5
+security.md.algoritm = SHA-256  
+
+### secure hash support: BCRYPT, ESAPICYPHER
+security.secure.hash.algorithm=BCRYPT
 security.passcode.salt=salt
 
 security.idleTimeoutDuration = 25M
@@ -76,7 +85,6 @@
 security.encryption.loadFactor = 8
 security.validation.stringLength = 150
 security.validation.emailLength = 50
-security.encryption.algo=BCRYPT
 security.sharedSecret=this-is-shared-secret-code-for-JWT-Signing.It-must-contains-minimum-256-bits
 security.adminToken=adminToken
 
diff --git a/full/src/test/resources/kustvakt-test.conf b/full/src/test/resources/kustvakt-test.conf
index cc53e79..694abce 100644
--- a/full/src/test/resources/kustvakt-test.conf
+++ b/full/src/test/resources/kustvakt-test.conf
@@ -89,7 +89,16 @@
 security.tokenTTL = 2S
 security.shortTokenTTL = 1S
 
-## specifies the user data field that is used to salt user passwords
+## see SecureRandom Number Generation Algorithms
+## default SHA1PRNG
+security.secure.random.algorithm=SHA1PRNG
+
+## see MessageDigest Algorithms
+## default MD5
+security.md.algoritm = SHA-256  
+
+### secure hash support: BCRYPT, ESAPICYPHER
+security.secure.hash.algorithm=BCRYPT
 security.passcode.salt=salt
 
 security.idleTimeoutDuration = 25M
@@ -100,7 +109,7 @@
 security.encryption.loadFactor = 8
 security.validation.stringLength = 150
 security.validation.emailLength = 50
-security.encryption.algo=BCRYPT
+
 security.sharedSecret=this-is-shared-secret-code-for-JWT-Signing.It-must-contains-minimum-256-bits
 
 ## applicable: rewrite, foundry, filter, deny