From a5a12b2f1f4a6ab86b1a81f99d2402fef7ae2eca Mon Sep 17 00:00:00 2001 From: Justin Richer Date: Fri, 22 Jul 2016 13:47:20 -0400 Subject: [PATCH] added assertion validation engine --- .../WhitelistedIssuerAssertionValidator.java | 105 ++++++++++++++++++ .../webapp/WEB-INF/application-context.xml | 3 + .../main/webapp/WEB-INF/assertion-config.xml | 43 +++++++ .../DynamicClientRegistrationEndpoint.java | 5 +- 4 files changed, 154 insertions(+), 2 deletions(-) create mode 100644 openid-connect-common/src/main/java/org/mitre/jwt/assertion/impl/WhitelistedIssuerAssertionValidator.java create mode 100644 openid-connect-server-webapp/src/main/webapp/WEB-INF/assertion-config.xml diff --git a/openid-connect-common/src/main/java/org/mitre/jwt/assertion/impl/WhitelistedIssuerAssertionValidator.java b/openid-connect-common/src/main/java/org/mitre/jwt/assertion/impl/WhitelistedIssuerAssertionValidator.java new file mode 100644 index 000000000..334f3f4ba --- /dev/null +++ b/openid-connect-common/src/main/java/org/mitre/jwt/assertion/impl/WhitelistedIssuerAssertionValidator.java @@ -0,0 +1,105 @@ +/******************************************************************************* + * Copyright 2016 The MITRE Corporation + * and the MIT Internet Trust Consortium + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + *******************************************************************************/ + +package org.mitre.jwt.assertion.impl; + +import java.text.ParseException; +import java.util.HashMap; +import java.util.Map; + +import org.mitre.jwt.assertion.AssertionValidator; +import org.mitre.jwt.signer.service.JWTSigningAndValidationService; +import org.mitre.jwt.signer.service.impl.JWKSetCacheService; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; + +import com.google.common.base.Strings; +import com.nimbusds.jwt.JWT; +import com.nimbusds.jwt.JWTClaimsSet; +import com.nimbusds.jwt.SignedJWT; + +/** + * Checks to see if the assertion was signed by a particular authority available from a whitelist + * @author jricher + * + */ +public class WhitelistedIssuerAssertionValidator implements AssertionValidator { + + private static Logger logger = LoggerFactory.getLogger(WhitelistedIssuerAssertionValidator.class); + + /** + * Map of issuer -> JWKSetUri + */ + private Map whitelist = new HashMap<>(); + + /** + * @return the whitelist + */ + public Map getWhitelist() { + return whitelist; + } + + /** + * @param whitelist the whitelist to set + */ + public void setWhitelist(Map whitelist) { + this.whitelist = whitelist; + } + + @Autowired + private JWKSetCacheService jwkCache; + + @Override + public boolean isValid(JWT assertion) { + + if (!(assertion instanceof SignedJWT)) { + // unsigned assertion + return false; + } + + JWTClaimsSet claims; + try { + claims = assertion.getJWTClaimsSet(); + } catch (ParseException e) { + logger.debug("Invalid assertion claims"); + return false; + } + + if (Strings.isNullOrEmpty(claims.getIssuer())) { + logger.debug("No issuer for assertion, rejecting"); + return false; + } + + if (!whitelist.containsKey(claims.getIssuer())) { + logger.debug("Issuer is not in whitelist, rejecting"); + return false; + } + + String jwksUri = whitelist.get(claims.getIssuer()); + + JWTSigningAndValidationService validator = jwkCache.getValidator(jwksUri); + + if (validator.validateSignature((SignedJWT) assertion)) { + return true; + } else { + return false; + } + + } + +} diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/application-context.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/application-context.xml index cab2a00b4..6a7e0be9f 100644 --- a/openid-connect-server-webapp/src/main/webapp/WEB-INF/application-context.xml +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/application-context.xml @@ -202,6 +202,9 @@ + + + diff --git a/openid-connect-server-webapp/src/main/webapp/WEB-INF/assertion-config.xml b/openid-connect-server-webapp/src/main/webapp/WEB-INF/assertion-config.xml new file mode 100644 index 000000000..7a7a494a2 --- /dev/null +++ b/openid-connect-server-webapp/src/main/webapp/WEB-INF/assertion-config.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/DynamicClientRegistrationEndpoint.java b/openid-connect-server/src/main/java/org/mitre/openid/connect/web/DynamicClientRegistrationEndpoint.java index bf3a9cfe9..4aa04fb2b 100644 --- a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/DynamicClientRegistrationEndpoint.java +++ b/openid-connect-server/src/main/java/org/mitre/openid/connect/web/DynamicClientRegistrationEndpoint.java @@ -102,7 +102,7 @@ public class DynamicClientRegistrationEndpoint { @Autowired @Qualifier("clientAssertionValidator") - private static AssertionValidator assertionValidator; + private AssertionValidator assertionValidator; /** * Logger for this class @@ -143,12 +143,12 @@ public class DynamicClientRegistrationEndpoint { // do validation on the fields try { + newClient = validateSoftwareStatement(newClient); // need to handle the software statement first because it might override requested values newClient = validateScopes(newClient); newClient = validateResponseTypes(newClient); newClient = validateGrantTypes(newClient); newClient = validateRedirectUris(newClient); newClient = validateAuth(newClient); - newClient = validateSoftwareStatement(newClient); } catch (ValidationException ve) { // validation failed, return an error m.addAttribute(JsonErrorView.ERROR, ve.getError()); @@ -321,6 +321,7 @@ public class DynamicClientRegistrationEndpoint { // do validation on the fields try { + newClient = validateSoftwareStatement(newClient); // need to handle the software statement first because it might override requested values newClient = validateScopes(newClient); newClient = validateResponseTypes(newClient); newClient = validateGrantTypes(newClient);