001/* 002 * (C) Copyright 2006-2020 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.Arrays; 022import java.util.Collection; 023import java.util.HashMap; 024import java.util.List; 025import java.util.Map; 026import java.util.stream.Collectors; 027 028import org.apache.logging.log4j.LogManager; 029import org.apache.logging.log4j.Logger; 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 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 Logger log = LogManager.getLogger(OpenIDConnectProviderRegistryImpl.class); 046 047 public static final String PROVIDER_EP = "providers"; 048 049 protected Map<String, OpenIDConnectProvider> providers = new HashMap<>(); 050 051 protected OAuth2ServiceProviderRegistry getOAuth2ServiceProviderRegistry() { 052 return Framework.getService(OAuth2ServiceProviderRegistry.class); 053 } 054 055 @Override 056 public void registerContribution(Object contribution, String extensionPoint, ComponentInstance contributor) { 057 if (PROVIDER_EP.equals(extensionPoint)) { 058 OpenIDConnectProviderDescriptor provider = (OpenIDConnectProviderDescriptor) contribution; 059 060 if (provider.getClientId() == null || provider.getClientSecret() == null) { 061 log.info( 062 "OpenId provider for {} is disabled because clientId and/or clientSecret are empty (component id = {})", 063 provider::getName, contributor::getName); 064 provider.setEnabled(false); 065 } 066 log.info("OpenId provider for {} will be registred at application startup", provider::getName); 067 // delay registration because data sources may not be available 068 // at this point 069 register(PROVIDER_EP, provider); 070 } 071 } 072 073 @Override 074 public Collection<OpenIDConnectProvider> getProviders() { 075 return providers.values(); 076 } 077 078 @Override 079 public Collection<OpenIDConnectProvider> getEnabledProviders() { 080 return getProviders().stream().filter(OpenIDConnectProvider::isEnabled).collect(Collectors.toList()); 081 } 082 083 @Override 084 public OpenIDConnectProvider getProvider(String name) { 085 return providers.get(name); 086 } 087 088 protected void registerPendingProviders() { 089 List<OpenIDConnectProviderDescriptor> providers = getDescriptors(PROVIDER_EP); 090 for (OpenIDConnectProviderDescriptor provider : providers) { 091 // former registry discarded disabled providers 092 if (provider.isEnabled()) { 093 registerOpenIdProvider(provider); 094 } 095 } 096 } 097 098 protected void registerOpenIdProvider(OpenIDConnectProviderDescriptor provider) { 099 100 OAuth2ServiceProviderRegistry oauth2ProviderRegistry = getOAuth2ServiceProviderRegistry(); 101 RedirectUriResolver redirectUriResolver; 102 try { 103 redirectUriResolver = provider.getRedirectUriResolver().getDeclaredConstructor().newInstance(); 104 } catch (ReflectiveOperationException e) { 105 throw new RuntimeException(e); 106 } 107 108 if (oauth2ProviderRegistry != null) { 109 110 OAuth2ServiceProvider oauth2Provider = oauth2ProviderRegistry.getProvider(provider.getName()); 111 112 if (oauth2Provider == null) { 113 oauth2Provider = oauth2ProviderRegistry.addProvider(provider.getName(), provider.getDescription(), 114 provider.getTokenServerURL(), provider.getAuthorizationServerURL(), provider.getClientId(), 115 provider.getClientSecret(), Arrays.asList(provider.getScopes())); 116 } else { 117 log.warn("Provider {} is already in the Database, XML contribution won't overwrite it", 118 provider::getName); 119 } 120 providers.put(provider.getName(), 121 new OpenIDConnectProvider(oauth2Provider, provider.getAccessTokenKey(), provider.getUserInfoURL(), 122 provider.getUserInfoClass(), provider.getIcon(), provider.isEnabled(), redirectUriResolver, 123 provider.getUserResolverClass(), provider.getUserMapper(), 124 provider.getAuthenticationMethod())); 125 126 // contribute icon and link to the Login Screen 127 LoginScreenHelper.registerSingleProviderLoginScreenConfig(provider.getName(), provider.getIcon(), 128 provider.getUserInfoURL(), provider.getLabel(), provider.getDescription(), 129 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 provider.getAuthenticationMethod())); 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}