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.service; 018 019import static org.forgerock.caf.authentication.framework.AuthenticationFramework.LOG; 020 021import java.net.URL; 022import java.security.PublicKey; 023import java.util.concurrent.ConcurrentHashMap; 024import java.util.concurrent.ConcurrentMap; 025 026import org.forgerock.jaspi.modules.openid.exceptions.FailedToLoadJWKException; 027import org.forgerock.jaspi.modules.openid.resolvers.OpenIdResolver; 028import org.forgerock.jaspi.modules.openid.resolvers.OpenIdResolverFactory; 029import org.forgerock.json.jose.utils.KeystoreManager; 030import org.forgerock.json.jose.utils.KeystoreManagerException; 031 032/** 033 * Holds a copy of the current OpenID Resolvers. 034 * 035 * As new resolvers are configured, this class loads up the appropriate verification key and 036 * stores it along with the other information necessary for it to perform its task. 037 * 038 * This service stores {@link org.forgerock.jaspi.modules.openid.resolvers.OpenIdResolver}s against their issuer key, 039 * so the appropriate {@link org.forgerock.jaspi.modules.openid.resolvers.OpenIdResolver} can be looked up. 040 */ 041public class OpenIdResolverServiceImpl implements OpenIdResolverService { 042 043 private final ConcurrentMap<String, OpenIdResolver> openIdResolvers = new ConcurrentHashMap<>(); 044 045 private final int readTimeout; 046 private final int connTimeout; 047 048 private final OpenIdResolverFactory openIdResolverFactory; 049 050 /** 051 * Constructor for the OpenIdResolverServiceImpl which will use the supplied 052 * read and connection timeouts when communicating over HTTP. 053 * 054 * @param readTimeout HTTP read timeout for resolvers 055 * @param connTimeout HTTP connection timeout for resolvers 056 */ 057 public OpenIdResolverServiceImpl(final int readTimeout, final int connTimeout) { 058 this.readTimeout = readTimeout; 059 this.connTimeout = connTimeout; 060 this.openIdResolverFactory = new OpenIdResolverFactory(readTimeout, connTimeout); 061 } 062 063 /** 064 * For tests. 065 * 066 * @param openIdResolverFactory Factory to provide resolvers 067 * @param readTimeout HTTP read timeout for resolvers 068 * @param connTimeout HTTP connection timeout for resolvers 069 */ 070 OpenIdResolverServiceImpl(OpenIdResolverFactory openIdResolverFactory, final int readTimeout, 071 final int connTimeout) { 072 this.readTimeout = readTimeout; 073 this.connTimeout = connTimeout; 074 this.openIdResolverFactory = openIdResolverFactory; 075 } 076 077 /** 078 * Returns the appropriate resolver for the given issuer - if it exists. Otherwise null. 079 * 080 * @param issuer The name of the issuer of the Open Id Connect token to check 081 * @return A resolver which can handle verification of the Open Id Connect token 082 */ 083 public OpenIdResolver getResolverForIssuer(final String issuer) { 084 return openIdResolvers.get(issuer); 085 } 086 087 /** 088 * Configures a new Resolver by finding the appropriate public key in the supplied keystore, 089 * and adds it to the Map of current resolvers. 090 * 091 * @param issuer The issuer which provides the Open ID Connect auth token 092 * @param keyAlias The alias under which the public key is stored 093 * @param keystoreLocation location of the keystore file 094 * @param keystoreType type of the keystore file 095 * @param keystorePassword password to enter the keystore 096 * @return true if the resolver was configured successfully, false otherwise 097 */ 098 public boolean configureResolverWithKey(final String issuer, 099 final String keyAlias, final String keystoreLocation, 100 final String keystoreType, final String keystorePassword) { 101 102 try { 103 // Do not need the private key password as we are only ever getting the public key 104 final KeystoreManager keystoreManager = new KeystoreManager(keystoreType, keystoreLocation, 105 keystorePassword); 106 final PublicKey key = keystoreManager.getPublicKey(keyAlias); 107 108 final OpenIdResolver impl = openIdResolverFactory.createPublicKeyResolver(issuer, key); 109 openIdResolvers.put(issuer, impl); 110 } catch (KeystoreManagerException kme) { 111 LOG.debug("Error accessing the KeystoreManager", kme); 112 return false; 113 } catch (NullPointerException npe) { 114 LOG.debug("No key found in keystore with appropriate alias", npe); 115 return false; 116 } 117 118 return true; 119 } 120 121 /** 122 * Configures a new Resolver by finding the appropriate public key in the supplied keystore, 123 * and adds it to the Map of current resolvers. 124 * 125 * @param issuer The issuer which provides the Open ID Connect auth token 126 * @param sharedSecret The known-to-both-parties secret String 127 * @return true if the resolver was configured successfully, false otherwise 128 */ 129 public boolean configureResolverWithSecret(final String issuer, final String sharedSecret) { 130 131 try { 132 final OpenIdResolver impl = openIdResolverFactory.createSharedSecretResolver(issuer, sharedSecret); 133 openIdResolvers.put(issuer, impl); 134 } catch (IllegalArgumentException iae) { 135 LOG.debug("Shared secret must not be null", iae); 136 return false; 137 } 138 139 return true; 140 } 141 142 /** 143 * Configures a new Resolver by setting it up to download public keys from the supplied url. 144 * 145 * @param issuer The issuer which provides the Open ID Connect auth token 146 * @param jwkUrl location from which to determine which public key to use 147 * @return true if the resolver was configured successfully, false otherwise 148 */ 149 public boolean configureResolverWithJWK(final String issuer, 150 final URL jwkUrl) { 151 152 try { 153 final OpenIdResolver impl = openIdResolverFactory.createJWKResolver(issuer, jwkUrl, 154 readTimeout, connTimeout); 155 openIdResolvers.put(issuer, impl); 156 } catch (FailedToLoadJWKException e) { 157 LOG.debug("Unable to load JSON Web Keys", e); 158 return false; 159 } 160 161 return true; 162 } 163 164 /** 165 * Configures a new Resolver by setting it up to download public keys from the supplied 166 * well-known Open Id Connect URL. 167 * 168 * @param configUrl location from which to determine which public key to use 169 * @return true if the resolver was configured successfully, false otherwise 170 */ 171 public boolean configureResolverWithWellKnownOpenIdConfiguration(final URL configUrl) { 172 173 try { 174 final OpenIdResolver impl = openIdResolverFactory.createFromOpenIDConfigUrl(configUrl); 175 openIdResolvers.put(impl.getIssuer(), impl); 176 } catch (FailedToLoadJWKException e) { 177 LOG.debug("Unable to load JSON Web Keys", e); 178 return false; 179 } 180 181 return true; 182 } 183 184}