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.MalformedURLException;
022import java.net.URL;
023import java.util.List;
024import java.util.Map;
025
026import org.forgerock.jaspi.modules.openid.resolvers.OpenIdResolver;
027
028/**
029 * Implementation of the {@link OpenIdResolverServiceConfigurator} interface which
030 * applies a simple priority ordering when reading a service configuration.
031 */
032public class OpenIdResolverServiceConfiguratorImpl implements OpenIdResolverServiceConfigurator {
033
034    /**
035     * This implementation includes a priority system for ensuring invalid configs still
036     * attempt to be loaded.
037     *
038     * Priority is:
039     * - OpenIDConfiguration
040     * - JWK Location
041     * - Keystore Location
042     * - Secret Key
043     * - Failure
044     *
045     * @param service to configure
046     * @param resolvers the configuration
047     * @return false if any resolver configuration fails true otherwise
048     */
049    public boolean configureService(final OpenIdResolverService service, final List<Map<String, String>> resolvers) {
050
051        if (resolvers == null || resolvers.size() < 1) {
052            return false;
053        }
054
055        boolean atLeastOne = false;
056
057        for (Map<String, String> resolverConfig : resolvers) {
058
059            final String keyAlias = resolverConfig.get(OpenIdResolver.KEY_ALIAS_KEY);
060            final String clientSecret = resolverConfig.get(OpenIdResolver.CLIENT_SECRET_KEY);
061            final String jwk = resolverConfig.get(OpenIdResolver.JWK);
062            final String openIdConfig = resolverConfig.get(OpenIdResolver.WELL_KNOWN_CONFIGURATION);
063
064            if (openIdConfig != null) {
065                atLeastOne = openIdConfiguration(service, openIdConfig);
066                continue;
067            }
068
069            final String issuer = resolverConfig.get(OpenIdResolver.ISSUER_KEY);
070
071            if (issuer == null) {
072                LOG.debug("No issuer name found for non-Open ID Configuration configured resolver");
073                continue;
074            }
075
076            if (jwk != null) {
077                atLeastOne = jwkConfiguration(service, jwk, issuer);
078                continue;
079            }
080
081            if (keyAlias != null) {
082
083                final String keystoreLocation = resolverConfig.get(OpenIdResolver.KEYSTORE_LOCATION_KEY);
084                final String keystorePass = resolverConfig.get(OpenIdResolver.KEYSTORE_PASS_KEY);
085                final String keystoreType = resolverConfig.get(OpenIdResolver.KEYSTORE_TYPE_KEY);
086
087                atLeastOne = keystoreConfiguration(service, keystoreLocation, keystorePass, keystoreType,
088                        keyAlias, issuer);
089                continue;
090            }
091
092            if (clientSecret != null) {
093                atLeastOne = sharedSecretConfiguration(service, clientSecret, issuer);
094            }
095        }
096
097        return atLeastOne;
098
099    }
100
101    /**
102     * Configures the service to hold a resolver whose configuration relies on keys stored
103     * in trust stores.
104     *
105     * @param service The service to configure with this resolver
106     * @param keystoreLocation The location of the trust store file
107     * @param keystorePass The password to the keystore
108     * @param keystoreType The type of keystore to which the location param points
109     * @param keyAlias The name under which the key is stored in the trust store
110     * @param issuer The provider (issuer) of the JWS
111     * @return True if the service is populated with a new resolver, false otherwise
112     */
113    private boolean keystoreConfiguration(OpenIdResolverService service, String keystoreLocation, String keystorePass,
114                                          String keystoreType, String keyAlias, String issuer) {
115
116        if ((keystoreLocation == null || keystoreLocation.isEmpty())
117                || (keystoreType == null || keystoreType.isEmpty())
118                || (keystorePass == null || keystorePass.isEmpty())) {
119            LOG.debug("Unable to configure resolver using keyAlias for {}", issuer);
120            return false;
121        }
122
123        if (!service.configureResolverWithKey(issuer, keyAlias,
124                keystoreLocation, keystoreType, keystorePass)) {
125            LOG.debug("Unable to configure resolver using keyAlias for {}", issuer);
126            return false;
127        } else {
128            return true;
129        }
130    }
131
132    /**
133     * Configures the service to hold a resolver which is generated by the use of a
134     * SharedSecret (String) converted into a SecretKey via HMAC.
135     *
136     * @param service The service to configure with this resolver
137     * @param secret The shared secret, known to both provider and client
138     * @param issuer The provider (issuer) of the JWS
139     * @return True if the service is populated with a new resolver, false otherwise
140     */
141    private boolean sharedSecretConfiguration(OpenIdResolverService service, String secret, String issuer) {
142        if (!service.configureResolverWithSecret(issuer, secret)) {
143            LOG.debug("Unable to configure resolver using sharedSecret for {}", issuer);
144            return false;
145        } else {
146            return true;
147        }
148    }
149
150    /**
151     * Configures the service to hold a resolver whose configuration has been drawn from
152     * a JWK set's URL.
153     *
154     * @param service The service to configure with this resolver
155     * @param jwk The URL of the configuration to use to generate the resolver
156     * @param issuer The issuer's name to which this resolver will respond through the service
157     * @return True if the service is populated with a new resolver, false otherwise
158     */
159    private boolean jwkConfiguration(OpenIdResolverService service, String jwk, String issuer) {
160
161        final URL jwkUrl;
162        try {
163            jwkUrl = new URL(jwk);
164        } catch (MalformedURLException e) {
165            LOG.debug("Supplied JWKs URL at {} is invalid.", jwk);
166            return false;
167        }
168
169        if (!service.configureResolverWithJWK(issuer, jwkUrl)) {
170            LOG.debug("Unable to configure resolver using JWK for {}", issuer);
171            return false;
172        } else {
173            return true;
174        }
175    }
176
177    /**
178     * Configures the service to hold a resolver whose configuration has been drawn from
179     * an Open ID Configuration URL.
180     *
181     * @param service The service to configure with this resolver
182     * @param openIdConfig The configuration to use to generate the resolver
183     * @return True if the service is populated with a new resolver, false otherwise
184     */
185    private boolean openIdConfiguration(OpenIdResolverService service, String openIdConfig) {
186
187        final URL configUrl;
188        try {
189            configUrl = new URL(openIdConfig);
190        } catch (MalformedURLException e) {
191            LOG.debug("Supplied JWKs URL at {} is invalid.", openIdConfig);
192            return false;
193        }
194
195        if (!service.configureResolverWithWellKnownOpenIdConfiguration(configUrl)) {
196            LOG.debug("Unable to configure resolver using Open ID Configuration at url: {}", openIdConfig);
197            return false;
198        } else {
199            return true;
200        }
201    }
202
203}