| package de.ids_mannheim.korap.config; |
| |
| import com.nimbusds.jose.*; |
| import com.nimbusds.jose.crypto.MACSigner; |
| import com.nimbusds.jose.crypto.MACVerifier; |
| import com.nimbusds.jwt.JWTClaimsSet; |
| import com.nimbusds.jwt.SignedJWT; |
| import de.ids_mannheim.korap.exceptions.KustvaktException; |
| import de.ids_mannheim.korap.exceptions.StatusCodes; |
| import de.ids_mannheim.korap.user.GenericUserData; |
| import de.ids_mannheim.korap.user.TokenContext; |
| import de.ids_mannheim.korap.user.User; |
| import de.ids_mannheim.korap.user.Userdata; |
| import de.ids_mannheim.korap.utils.TimeUtils; |
| import org.joda.time.DateTime; |
| |
| import java.net.MalformedURLException; |
| import java.net.URL; |
| import java.text.ParseException; |
| import java.util.Map; |
| |
| /** |
| * @author hanl |
| * @date 19/05/2014 |
| */ |
| public class JWTSigner { |
| |
| private URL issuer; |
| private JWSSigner signer; |
| private JWSVerifier verifier; |
| private final int defaultttl; |
| |
| |
| public JWTSigner (final byte[] secret, URL issuer, final int defaulttl) { |
| this.issuer = issuer; |
| this.signer = new MACSigner(secret); |
| this.verifier = new MACVerifier(secret); |
| this.defaultttl = defaulttl; |
| } |
| |
| |
| public JWTSigner (final byte[] secret, String issuer) |
| throws MalformedURLException { |
| this(secret, new URL(issuer), 72 * 60 * 60); |
| } |
| |
| |
| public SignedJWT createJWT (User user, Map<String, Object> attr) { |
| return signContent(user, attr, defaultttl); |
| } |
| |
| |
| public SignedJWT signContent (User user, Map<String, Object> attr, int ttl) { |
| String scopes; |
| |
| JWTClaimsSet cs = new JWTClaimsSet(); |
| cs.setIssuerClaim(this.issuer.toString()); |
| |
| if ((scopes = (String) attr.get(Attributes.SCOPES)) != null) { |
| Userdata data = new GenericUserData(); |
| data.readQuietly(attr, false); |
| Scopes claims = Scopes.mapScopes(scopes, data); |
| cs.setCustomClaims(claims.toMap()); |
| } |
| |
| cs.setSubjectClaim(user.getUsername()); |
| if (attr.get(Attributes.CLIENT_ID) != null) |
| cs.setAudienceClaim(new String[] { (String) attr |
| .get(Attributes.CLIENT_ID) }); |
| cs.setExpirationTimeClaim(TimeUtils.getNow().plusSeconds(ttl) |
| .getMillis()); |
| SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), |
| cs); |
| try { |
| signedJWT.sign(signer); |
| } |
| catch (JOSEException e) { |
| return null; |
| } |
| return signedJWT; |
| } |
| |
| |
| /** |
| * @param username |
| * @param json |
| * @return |
| */ |
| public SignedJWT signContent (String username, String userclient, |
| String json, int ttl) { |
| JWTClaimsSet cs = new JWTClaimsSet(); |
| cs.setSubjectClaim(username); |
| if (!json.isEmpty()) |
| cs.setCustomClaim("data", json); |
| cs.setExpirationTimeClaim(TimeUtils.getNow().plusSeconds(ttl) |
| .getMillis()); |
| cs.setIssuerClaim(this.issuer.toString()); |
| |
| if (!userclient.isEmpty()) |
| cs.setCustomClaim("userip", userclient); |
| |
| SignedJWT signedJWT = new SignedJWT(new JWSHeader(JWSAlgorithm.HS256), |
| cs); |
| try { |
| signedJWT.sign(signer); |
| } |
| catch (JOSEException e) { |
| return null; |
| } |
| return signedJWT; |
| } |
| |
| |
| public SignedJWT signContent (String username, String userclient, |
| String json) { |
| return signContent(username, userclient, json, defaultttl); |
| } |
| |
| |
| public SignedJWT createSignedToken (String username) { |
| return createSignedToken(username, defaultttl); |
| } |
| |
| |
| // add client info |
| public SignedJWT createSignedToken (String username, int ttl) { |
| return signContent(username, "", "", ttl); |
| } |
| |
| |
| public SignedJWT verifyToken (String token) throws KustvaktException { |
| SignedJWT client; |
| try { |
| client = SignedJWT.parse(token); |
| if (!client.verify(verifier)) |
| throw new KustvaktException(StatusCodes.REQUEST_INVALID); |
| |
| if (!new DateTime(client.getJWTClaimsSet().getExpirationTimeClaim()) |
| .isAfterNow()) |
| throw new KustvaktException(StatusCodes.EXPIRED, |
| "authentication token is expired", token); |
| } |
| catch (ParseException | JOSEException e) { |
| //todo: message or entity, how to treat??! |
| throw new KustvaktException(StatusCodes.ILLEGAL_ARGUMENT, |
| "token could not be verified", token); |
| } |
| return client; |
| } |
| |
| |
| // does not care about expiration times |
| public String retrieveContent (String signedContent) |
| throws KustvaktException { |
| SignedJWT jwt; |
| try { |
| jwt = SignedJWT.parse(signedContent); |
| if (!jwt.verify(verifier)) |
| throw new KustvaktException(StatusCodes.REQUEST_INVALID, |
| "token invalid", signedContent); |
| return (String) jwt.getJWTClaimsSet().getCustomClaim("data"); |
| } |
| catch (ParseException | JOSEException e) { |
| return null; |
| } |
| } |
| |
| |
| public TokenContext getTokenContext (String idtoken) throws ParseException, |
| JOSEException, KustvaktException { |
| SignedJWT signedJWT = verifyToken(idtoken); |
| |
| TokenContext c = new TokenContext(); |
| c.setUsername(signedJWT.getJWTClaimsSet().getSubjectClaim()); |
| if (signedJWT.getJWTClaimsSet().getAudienceClaim() != null) |
| c.addContextParameter(Attributes.CLIENT_ID, signedJWT |
| .getJWTClaimsSet().getAudienceClaim()[0]); |
| c.setExpirationTime(signedJWT.getJWTClaimsSet() |
| .getExpirationTimeClaim()); |
| c.setToken(idtoken); |
| c.addParams(signedJWT.getJWTClaimsSet().getCustomClaims()); |
| return c; |
| } |
| |
| } |