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}