001/*
002 * (C) Copyright 2006-2017 Nuxeo (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Nelson Silva
018 */
019package org.nuxeo.ecm.platform.oauth2.openid;
020
021import java.util.ArrayList;
022import java.util.Arrays;
023import java.util.Collection;
024import java.util.HashMap;
025import java.util.List;
026import java.util.Map;
027
028import org.apache.commons.logging.Log;
029import org.apache.commons.logging.LogFactory;
030import org.nuxeo.ecm.platform.oauth2.providers.OAuth2ServiceProvider;
031import org.nuxeo.ecm.platform.oauth2.providers.OAuth2ServiceProviderRegistry;
032import org.nuxeo.ecm.platform.ui.web.auth.LoginScreenHelper;
033import org.nuxeo.runtime.api.Framework;
034import org.nuxeo.runtime.model.ComponentContext;
035import org.nuxeo.runtime.model.ComponentInstance;
036import org.nuxeo.runtime.model.DefaultComponent;
037
038/**
039 * @author Nelson Silva <nelson.silva@inevo.pt>
040 * @author <a href="mailto:tdelprat@nuxeo.com">Tiry</a>
041 * @since 5.7
042 */
043public class OpenIDConnectProviderRegistryImpl extends DefaultComponent implements OpenIDConnectProviderRegistry {
044
045    protected static final Log log = LogFactory.getLog(OpenIDConnectProviderRegistryImpl.class);
046
047    public static final String PROVIDER_EP = "providers";
048
049    protected Map<String, OpenIDConnectProvider> providers = new HashMap<>();
050
051    protected OpenIDProviderFragmentRegistry pendingProviders = new OpenIDProviderFragmentRegistry();
052
053    protected OAuth2ServiceProviderRegistry getOAuth2ServiceProviderRegistry() {
054        return Framework.getLocalService(OAuth2ServiceProviderRegistry.class);
055    }
056
057    @Override
058    public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) {
059        if (PROVIDER_EP.equals(extensionPoint)) {
060            OpenIDConnectProviderDescriptor provider = (OpenIDConnectProviderDescriptor) contribution;
061
062            if (provider.getClientId() == null || provider.getClientSecret() == null) {
063                log.info("OpenId provider for " + provider.getName()
064                        + " is disabled because clientId and/or clientSecret are empty (component id = "
065                        + contributor.getName().toString() + ")");
066                provider.setEnabled(false);
067            }
068            log.info("OpenId provider for " + provider.getName() + " will be registred at application startup");
069            // delay registration because data sources may not be available
070            // at this point
071            pendingProviders.addContribution(provider);
072        }
073    }
074
075    @Override
076    public Collection<OpenIDConnectProvider> getProviders() {
077        return providers.values();
078    }
079
080    @Override
081    public Collection<OpenIDConnectProvider> getEnabledProviders() {
082        List<OpenIDConnectProvider> result = new ArrayList<>();
083        for (OpenIDConnectProvider provider : getProviders()) {
084            if (provider.isEnabled()) {
085                result.add(provider);
086            }
087        }
088        return result;
089    }
090
091    @Override
092    public OpenIDConnectProvider getProvider(String name) {
093        return providers.get(name);
094    }
095
096    protected void registerPendingProviders() {
097        for (OpenIDConnectProviderDescriptor provider : pendingProviders.getContribs()) {
098            registerOpenIdProvider(provider);
099        }
100    }
101
102    protected void registerOpenIdProvider(OpenIDConnectProviderDescriptor provider) {
103
104        OAuth2ServiceProviderRegistry oauth2ProviderRegistry = getOAuth2ServiceProviderRegistry();
105        RedirectUriResolver redirectUriResolver;
106        try {
107            redirectUriResolver = provider.getRedirectUriResolver().newInstance();
108        } catch (ReflectiveOperationException e) {
109            throw new RuntimeException(e);
110        }
111
112        if (oauth2ProviderRegistry != null) {
113
114            OAuth2ServiceProvider oauth2Provider = oauth2ProviderRegistry.getProvider(provider.getName());
115
116            if (oauth2Provider == null) {
117                oauth2Provider = oauth2ProviderRegistry.addProvider(provider.getName(), provider.getDescription(),
118                        provider.getTokenServerURL(), provider.getAuthorizationServerURL(), provider.getClientId(),
119                        provider.getClientSecret(), Arrays.asList(provider.getScopes()));
120            } else {
121                log.warn("Provider " + provider.getName()
122                        + " is already in the Database, XML contribution  won't overwrite it");
123            }
124            providers.put(provider.getName(), new OpenIDConnectProvider(oauth2Provider, provider.getAccessTokenKey(),
125                    provider.getUserInfoURL(), provider.getUserInfoClass(), provider.getIcon(), provider.isEnabled(),
126                    redirectUriResolver, provider.getUserResolverClass(), provider.getUserMapper()));
127
128            // contribute icon and link to the Login Screen
129            LoginScreenHelper.registerLoginProvider(provider.getName(), provider.getIcon(), provider.getUserInfoURL(),
130                    provider.getLabel(), provider.getDescription(), providers.get(provider.getName()));
131
132        } else {
133            if (Framework.isTestModeSet()) {
134                providers.put(provider.getName(),
135                        new OpenIDConnectProvider(null, provider.getAccessTokenKey(), provider.getUserInfoURL(),
136                                provider.getUserInfoClass(), provider.getIcon(), provider.isEnabled(),
137                                redirectUriResolver, provider.getUserResolverClass(),provider.getUserMapper()));
138            } else {
139                log.error("Can not register OAuth Provider since OAuth Registry is not available");
140            }
141        }
142
143    }
144
145    @Override
146    public void start(ComponentContext context) {
147        registerPendingProviders();
148    }
149
150}