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