Fixed issue #27.
Change-Id: I8332bd16db791483c41b614f508b49b2b092a257
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