converted bearer assertion framework to nimbus-jose
parent
910a6cf1a0
commit
c7d1b47b38
|
@ -5,10 +5,11 @@ package org.mitre.openid.connect.assertion;
|
|||
|
||||
import java.util.Collection;
|
||||
|
||||
import org.mitre.jwt.model.Jwt;
|
||||
import org.springframework.security.authentication.AbstractAuthenticationToken;
|
||||
import org.springframework.security.core.GrantedAuthority;
|
||||
|
||||
import com.nimbusds.jwt.JWT;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
*
|
||||
|
@ -16,16 +17,27 @@ import org.springframework.security.core.GrantedAuthority;
|
|||
public class JwtBearerAssertionAuthenticationToken extends AbstractAuthenticationToken {
|
||||
|
||||
private String clientId;
|
||||
private Jwt jwt;
|
||||
private JWT jwt;
|
||||
|
||||
public JwtBearerAssertionAuthenticationToken(String clientId, Jwt jwt) {
|
||||
/**
|
||||
* Create an unauthenticated token with the given client ID and jwt
|
||||
* @param clientId
|
||||
* @param jwt
|
||||
*/
|
||||
public JwtBearerAssertionAuthenticationToken(String clientId, JWT jwt) {
|
||||
super(null);
|
||||
this.clientId = clientId;
|
||||
this.jwt = jwt;
|
||||
setAuthenticated(false);
|
||||
}
|
||||
|
||||
public JwtBearerAssertionAuthenticationToken(String clientId, Jwt jwt, Collection<? extends GrantedAuthority> authorities) {
|
||||
/**
|
||||
* Create an authenticated token with the given clientID, jwt, and authorities set
|
||||
* @param clientId
|
||||
* @param jwt
|
||||
* @param authorities
|
||||
*/
|
||||
public JwtBearerAssertionAuthenticationToken(String clientId, JWT jwt, Collection<? extends GrantedAuthority> authorities) {
|
||||
super(authorities);
|
||||
this.clientId = clientId;
|
||||
this.jwt = jwt;
|
||||
|
@ -65,14 +77,14 @@ public class JwtBearerAssertionAuthenticationToken extends AbstractAuthenticatio
|
|||
/**
|
||||
* @return the jwt
|
||||
*/
|
||||
public Jwt getJwt() {
|
||||
public JWT getJwt() {
|
||||
return jwt;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param jwt the jwt to set
|
||||
*/
|
||||
public void setJwt(Jwt jwt) {
|
||||
public void setJwt(JWT jwt) {
|
||||
this.jwt = jwt;
|
||||
}
|
||||
|
||||
|
|
|
@ -3,39 +3,25 @@
|
|||
*/
|
||||
package org.mitre.openid.connect.assertion;
|
||||
|
||||
import java.security.NoSuchAlgorithmException;
|
||||
import java.security.PublicKey;
|
||||
import java.security.interfaces.RSAPublicKey;
|
||||
import java.text.ParseException;
|
||||
import java.util.Date;
|
||||
import java.util.Arrays;
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
import org.mitre.jwt.model.Jwt;
|
||||
import org.mitre.jwt.model.JwtClaims;
|
||||
import org.mitre.jwt.model.JwtHeader;
|
||||
import org.mitre.jwt.signer.JwsAlgorithm;
|
||||
import org.mitre.jwt.signer.JwtSigner;
|
||||
import org.mitre.jwt.signer.impl.RsaSigner;
|
||||
import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
|
||||
import org.mitre.jwt.signer.service.impl.DefaultJwtSigningAndValidationService;
|
||||
import org.mitre.key.fetch.KeyFetcher;
|
||||
import org.mitre.oauth2.exception.ClientNotFoundException;
|
||||
import org.mitre.oauth2.model.ClientDetailsEntity;
|
||||
import org.mitre.oauth2.service.ClientDetailsEntityService;
|
||||
import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
|
||||
import org.mitre.openid.connect.config.OIDCServerConfiguration;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import org.springframework.beans.factory.annotation.Autowired;
|
||||
import org.springframework.security.authentication.AuthenticationProvider;
|
||||
import org.springframework.security.authentication.AuthenticationServiceException;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.core.userdetails.UserDetails;
|
||||
import org.springframework.security.core.userdetails.UsernameNotFoundException;
|
||||
|
||||
import com.nimbusds.jose.JOSEException;
|
||||
|
@ -43,7 +29,7 @@ import com.nimbusds.jose.JWSObject;
|
|||
import com.nimbusds.jose.JWSVerifier;
|
||||
import com.nimbusds.jose.crypto.RSASSAVerifier;
|
||||
import com.nimbusds.jwt.JWT;
|
||||
import com.nimbusds.jwt.JWTParser;
|
||||
import com.nimbusds.jwt.ReadOnlyJWTClaimsSet;
|
||||
|
||||
/**
|
||||
* @author jricher
|
||||
|
@ -79,8 +65,8 @@ public class JwtBearerAuthenticationProvider implements AuthenticationProvider {
|
|||
try {
|
||||
ClientDetailsEntity client = clientService.loadClientByClientId(jwtAuth.getClientId());
|
||||
|
||||
Jwt jwt = jwtAuth.getJwt();
|
||||
JwtClaims jwtClaims = jwt.getClaims();
|
||||
JWT jwt = jwtAuth.getJwt();
|
||||
ReadOnlyJWTClaimsSet jwtClaims = jwt.getJWTClaimsSet();
|
||||
|
||||
// check the signature with nimbus
|
||||
JWSVerifier verifier = getVerifierForClient(client);
|
||||
|
@ -90,20 +76,22 @@ public class JwtBearerAuthenticationProvider implements AuthenticationProvider {
|
|||
}
|
||||
|
||||
// check the issuer
|
||||
if (jwtClaims.getIssuer() == null) {
|
||||
if (jwtClaims.getIssuerClaim() == null) {
|
||||
throw new AuthenticationServiceException("Assertion Token Issuer is null");
|
||||
} else if (!jwtClaims.getIssuer().equals(client.getClientId())){
|
||||
throw new AuthenticationServiceException("Issuers do not match, expected " + client.getClientId() + " got " + jwtClaims.getIssuer());
|
||||
} else if (!jwtClaims.getIssuerClaim().equals(client.getClientId())){
|
||||
throw new AuthenticationServiceException("Issuers do not match, expected " + client.getClientId() + " got " + jwtClaims.getIssuerClaim());
|
||||
}
|
||||
|
||||
// check expiration
|
||||
if (jwtClaims.getExpiration() == null) {
|
||||
/*
|
||||
* FIXME: re-institute date check for Nimbus
|
||||
if (jwtClaims.getExpirationTimeClaim() == null) {
|
||||
throw new AuthenticationServiceException("Assertion Token does not have required expiration claim");
|
||||
} else {
|
||||
// it's not null, see if it's expired
|
||||
Date now = new Date(System.currentTimeMillis() - (timeSkewAllowance * 1000));
|
||||
if (now.after(jwtClaims.getExpiration())) {
|
||||
throw new AuthenticationServiceException("Assertion Token is expired: " + jwtClaims.getExpiration());
|
||||
if (now.after(jwtClaims.getExpirationTimeClaim())) {
|
||||
throw new AuthenticationServiceException("Assertion Token is expired: " + jwtClaims.getExpirationTimeClaim());
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -115,13 +103,6 @@ public class JwtBearerAuthenticationProvider implements AuthenticationProvider {
|
|||
}
|
||||
}
|
||||
|
||||
// check audience
|
||||
if (jwtClaims.getAudience() == null) {
|
||||
throw new AuthenticationServiceException("Assertion token audience is null");
|
||||
} else if (!jwtClaims.getAudience().contains(config.getIssuer())) {
|
||||
throw new AuthenticationServiceException("Audience does not match, expected " + config.getIssuer() + " got " + jwtClaims.getAudience());
|
||||
}
|
||||
|
||||
// check issued at
|
||||
if (jwtClaims.getIssuedAt() != null) {
|
||||
// since it's not null, see if it was issued in the future
|
||||
|
@ -130,7 +111,16 @@ public class JwtBearerAuthenticationProvider implements AuthenticationProvider {
|
|||
throw new AuthenticationServiceException("Assertion Token was issued in the future: " + jwtClaims.getIssuedAt());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
*/
|
||||
|
||||
// check audience
|
||||
if (jwtClaims.getAudienceClaim() == null) {
|
||||
throw new AuthenticationServiceException("Assertion token audience is null");
|
||||
} else if (!Arrays.asList(jwtClaims.getAudienceClaim()).contains(config.getIssuer())) { // FIXME: change back to list.contains() check after Nimbus update
|
||||
throw new AuthenticationServiceException("Audience does not match, expected " + config.getIssuer() + " got " + jwtClaims.getAudienceClaim());
|
||||
}
|
||||
|
||||
// IFF we managed to get all the way down here, the token is valid
|
||||
return new JwtBearerAssertionAuthenticationToken(client.getClientId(), jwt, client.getAuthorities());
|
||||
|
||||
|
|
|
@ -4,20 +4,20 @@
|
|||
package org.mitre.openid.connect.assertion;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.text.ParseException;
|
||||
|
||||
import javax.servlet.ServletException;
|
||||
import javax.servlet.http.HttpServletRequest;
|
||||
import javax.servlet.http.HttpServletResponse;
|
||||
|
||||
import org.mitre.jwt.model.Jwt;
|
||||
import org.springframework.security.authentication.BadCredentialsException;
|
||||
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
|
||||
import org.springframework.security.core.Authentication;
|
||||
import org.springframework.security.core.AuthenticationException;
|
||||
import org.springframework.security.oauth2.provider.client.ClientCredentialsTokenEndpointFilter;
|
||||
import org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter;
|
||||
|
||||
import com.google.common.base.Strings;
|
||||
import com.nimbusds.jwt.JWT;
|
||||
import com.nimbusds.jwt.JWTParser;
|
||||
|
||||
/**
|
||||
* Filter to check client authentication via JWT Bearer assertions.
|
||||
|
@ -48,14 +48,14 @@ public class JwtBearerClientAssertionTokenEndpointFilter extends ClientCredentia
|
|||
String assertion = request.getParameter("client_assertion");
|
||||
|
||||
try {
|
||||
Jwt jwt = Jwt.parse(assertion);
|
||||
JWT jwt = JWTParser.parse(assertion);
|
||||
|
||||
String clientId = jwt.getClaims().getSubject();
|
||||
String clientId = jwt.getJWTClaimsSet().getSubjectClaim();
|
||||
|
||||
Authentication authRequest = new JwtBearerAssertionAuthenticationToken(clientId, jwt);
|
||||
|
||||
return this.getAuthenticationManager().authenticate(authRequest);
|
||||
} catch (IllegalArgumentException e) {
|
||||
} catch (ParseException e) {
|
||||
throw new BadCredentialsException("Invalid JWT credential: " + assertion);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue