NimbusJwt.java
package org.europa.together.application;
import com.nimbusds.jose.JWSAlgorithm;
import com.nimbusds.jose.JWSHeader;
import com.nimbusds.jose.JWSObject;
import com.nimbusds.jose.JWSSigner;
import com.nimbusds.jose.JWSVerifier;
import com.nimbusds.jose.Payload;
import com.nimbusds.jose.crypto.MACSigner;
import com.nimbusds.jose.crypto.MACVerifier;
import com.nimbusds.jwt.JWTClaimsSet;
import com.nimbusds.jwt.SignedJWT;
import java.util.Date;
import java.util.List;
import org.europa.together.business.ConfigurationDAO;
import org.europa.together.business.CryptoTools;
import org.europa.together.business.JsonWebToken;
import org.europa.together.business.Logger;
import org.europa.together.domain.ConfigurationDO;
import org.europa.together.domain.HashAlgorithm;
import org.europa.together.domain.LogLevel;
import org.europa.together.exceptions.DAOException;
import org.europa.together.exceptions.JsonProcessingException;
import org.europa.together.utils.Constraints;
import org.europa.together.utils.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;
/**
* Implementation of JSON Web Token.
*/
@Repository
@Transactional
public class NimbusJwt implements JsonWebToken {
private static final long serialVersionUID = 16L;
private static final Logger LOGGER = new LogbackLogger(NimbusJwt.class);
private static final int INT_30 = 30;
private String sharedSecret = "";
private String issuer = "";
private String subject = "";
//1000 * 60 * 10 := 10 minutes = 600000
private int expieredTime = 0;
@Autowired
private ConfigurationDAO configurationDAO;
@Autowired
private CryptoTools cryptoTools;
/**
* Constructor.
*
* @throws DAOException case of error
*/
public NimbusJwt() throws DAOException {
LOGGER.log("instance class", LogLevel.INFO);
}
@Override
public String buildHMAC512SignedJws(final String jsonPayload)
throws JsonProcessingException {
String jws = "";
try {
proccessDbConfiguration();
JWSSigner signer = new MACSigner(sharedSecret);
JWSHeader jswHeader = new JWSHeader(JWSAlgorithm.HS512);
Payload payload = new Payload(jsonPayload);
JWSObject jwsObject = new JWSObject(jswHeader, payload);
jwsObject.sign(signer);
jws = jwsObject.serialize();
} catch (Exception ex) {
throw new JsonProcessingException(ex.getClass().getTypeName()
+ " " + ex.getMessage());
}
return jws;
}
@Override
public String buildHMAC512SignedJwt(final String issuer, final String subject,
final List<String> audience)
throws JsonProcessingException {
String jwt = "";
try {
proccessDbConfiguration();
JWSSigner signer = new MACSigner(sharedSecret);
JWSHeader jswHeader = new JWSHeader(JWSAlgorithm.HS512);
Date currentTime = new Date();
JWTClaimsSet jwtClaims = new JWTClaimsSet.Builder()
.issuer(issuer)
.subject(subject)
.audience(audience)
.expirationTime(new Date(new Date().getTime() + expieredTime))
.notBeforeTime(currentTime)
.issueTime(currentTime)
.jwtID(StringUtils.generateUUID())
.build();
SignedJWT signedJWT = new SignedJWT(jswHeader, jwtClaims);
signedJWT.sign(signer);
jwt = signedJWT.serialize();
} catch (Exception ex) {
throw new JsonProcessingException(ex.getClass().getTypeName()
+ " " + ex.getMessage());
}
return jwt;
}
@Override
public String buildHMAC512SignedJwt(final List<String> audience)
throws JsonProcessingException {
return this.buildHMAC512SignedJwt(this.issuer, this.subject, audience);
}
@Override
public String parseHMAC512SingedJws(final String jws)
throws JsonProcessingException {
String payload = "";
try {
proccessDbConfiguration();
JWSObject jwsObject = JWSObject.parse(jws);
JWSVerifier verifier = new MACVerifier(sharedSecret);
payload = jwsObject.getPayload().toString();
if (!jwsObject.verify(verifier)) {
LOGGER.log("JWS is not valid.", LogLevel.ERROR);
LOGGER.log("\t payload: " + payload, LogLevel.ERROR);
throw new JsonProcessingException(
"JWS is not valid. - for security reasons rejected!");
}
} catch (Exception ex) {
throw new JsonProcessingException(ex.getClass().getTypeName()
+ " " + ex.getMessage());
}
return payload;
}
@Override
public String parseHMAC512SingedJwt(final String jwt)
throws JsonProcessingException {
String payload = "";
try {
proccessDbConfiguration();
SignedJWT signedJWT = SignedJWT.parse(jwt);
JWSVerifier verifier = new MACVerifier(sharedSecret);
payload = signedJWT.getPayload().toString();
//TODO: extract for validation
if (!signedJWT.verify(verifier)) {
LOGGER.log("JWT is not valid.", LogLevel.ERROR);
LOGGER.log("\t payload: " + payload, LogLevel.ERROR);
throw new Exception("JWT is not valid. - for security reasons rejected!");
}
} catch (Exception ex) {
throw new JsonProcessingException(ex.getClass().getTypeName()
+ " " + ex.getMessage());
}
return payload;
}
//--------------------------------------------------------------------------
private void proccessDbConfiguration() throws DAOException {
List<ConfigurationDO> configurationEntries = configurationDAO
.getAllConfigurationSetEntries(Constraints.MODULE_NAME, CONFIG_VERSION, CONFIG_SET);
LOGGER.log("Process JWT Configuration [" + configurationEntries.size()
+ "] (" + configurationEntries.toString() + ")", LogLevel.DEBUG);
for (ConfigurationDO entry : configurationEntries) {
String value;
if (StringUtils.isEmpty(entry.getValue())) {
value = entry.getDefaultValue();
} else {
value = entry.getValue();
}
if (entry.getKey()
.equals(cryptoTools.calculateHash("json.sharedSecret",
HashAlgorithm.SHA256))) {
this.sharedSecret = value;
LOGGER.log("SharedSecret: " + value, LogLevel.DEBUG);
} else if (entry.getKey()
.equals(cryptoTools.calculateHash("json.issuer",
HashAlgorithm.SHA256))) {
this.issuer = value;
LOGGER.log("Issuer: " + value, LogLevel.DEBUG);
} else if (entry.getKey()
.equals(cryptoTools.calculateHash("json.subject",
HashAlgorithm.SHA256))) {
this.subject = value;
LOGGER.log("Subiject: " + value, LogLevel.DEBUG);
} else if (entry.getKey()
.equals(cryptoTools.calculateHash("json.expiration.time",
HashAlgorithm.SHA256))) {
this.expieredTime = Integer.parseInt(value);
LOGGER.log("Timeout: " + value, LogLevel.DEBUG);
}
}
LOGGER.log("Config: \n"
+ "\t SharedSecret: " + this.sharedSecret + "\n"
+ "\t Issuer: " + this.issuer + "\n"
+ "\t Subiject: " + this.subject + "\n"
+ "\t Timeout: " + this.expieredTime, LogLevel.DEBUG);
}
}