001/* 002* The contents of this file are subject to the terms of the Common Development and 003* Distribution License (the License). You may not use this file except in compliance with the 004* License. 005* 006* You can obtain a copy of the License at legal/CDDLv1.0.txt. See the License for the 007* specific language governing permission and limitations under the License. 008* 009* When distributing Covered Software, include this CDDL Header Notice in each file and include 010* the License file at legal/CDDLv1.0.txt. If applicable, add the following below the CDDL 011* Header, with the fields enclosed by brackets [] replaced by your own identifying 012* information: "Portions copyright [year] [name of copyright owner]". 013* 014* Copyright 2014-2015 ForgeRock AS. 015*/ 016 017package org.forgerock.jaspi.modules.openid.resolvers; 018 019import static org.forgerock.caf.authentication.framework.AuthenticationFramework.LOG; 020 021import java.nio.charset.Charset; 022 023import org.forgerock.jaspi.modules.openid.exceptions.InvalidSignatureException; 024import org.forgerock.jaspi.modules.openid.exceptions.OpenIdConnectVerificationException; 025import org.forgerock.json.jose.jws.SignedJwt; 026import org.forgerock.json.jose.jws.SigningManager; 027 028/** 029 * This class exists to allow functionality for those Open ID Connect providers which 030 * supply their signatures through symmetric key algorithms (e.g. HMAC). In these cases 031 * we want to use the shared secret (known to both the provider and client) such that we can 032 * generate a "private key". We do this using the SecretKeySpec call in 033 * {@link SharedSecretOpenIdResolverImpl#verifySignature}. 034 */ 035public class SharedSecretOpenIdResolverImpl extends BaseOpenIdResolver { 036 037 private final SigningManager signingManager; 038 039 private final String sharedSecret; 040 041 /** 042 * Constructor for SharedSecretOpenIdResolverImpl. 043 * 044 * @param issuer The issuer (provider) of the Open Id Connect id token 045 * @param sharedSecret The secret String, known to both provider and consumer 046 * @throws IllegalArgumentException if the sharedSecret is null 047 */ 048 public SharedSecretOpenIdResolverImpl(String issuer, String sharedSecret) { 049 super(issuer); 050 051 signingManager = new SigningManager(); 052 if (sharedSecret == null) { 053 throw new IllegalArgumentException("sharedSecret must not be null."); 054 } 055 056 this.sharedSecret = sharedSecret; 057 } 058 059 /** 060 * {@inheritDoc} 061 */ 062 @Override 063 public void validateIdentity(final SignedJwt idClaim) throws OpenIdConnectVerificationException { 064 super.validateIdentity(idClaim); 065 verifySignature(idClaim); 066 } 067 068 /** 069 * Verifies that the JWS was signed by the supplied key. Throws an exception otherwise. 070 * 071 * @param idClaim The JWS to verify 072 * @throws InvalidSignatureException If the JWS supplied does not match the key for this resolver 073 */ 074 public void verifySignature(final SignedJwt idClaim) throws InvalidSignatureException { 075 if (!idClaim.verify(signingManager.newHmacSigningHandler(sharedSecret.getBytes(Charset.forName("UTF-8"))))) { 076 LOG.debug("JWS signature not signed with supplied key"); 077 throw new InvalidSignatureException("JWS signature not signed with supplied key"); 078 } 079 } 080}