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