/* * Copyright 2017 ThoughtWorks, Inc. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.thoughtworks.go.server.security.providers; import com.thoughtworks.go.config.CaseInsensitiveString; import com.thoughtworks.go.config.PluginRoleConfig; import com.thoughtworks.go.config.SecurityAuthConfig; import com.thoughtworks.go.plugin.access.authentication.AuthenticationExtension; import com.thoughtworks.go.plugin.access.authentication.AuthenticationPluginRegistry; import com.thoughtworks.go.plugin.access.authentication.models.User; import com.thoughtworks.go.plugin.access.authorization.AuthorizationExtension; import com.thoughtworks.go.plugin.access.authorization.AuthorizationMetadataStore; import com.thoughtworks.go.plugin.access.authorization.models.AuthenticationResponse; import com.thoughtworks.go.plugin.domain.authorization.AuthorizationPluginInfo; import com.thoughtworks.go.server.security.AuthorityGranter; import com.thoughtworks.go.server.security.userdetail.GoUserPrinciple; import com.thoughtworks.go.server.service.GoConfigService; import com.thoughtworks.go.server.service.PluginRoleService; import com.thoughtworks.go.server.service.UserService; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.AuthenticationException; import org.springframework.security.providers.UsernamePasswordAuthenticationToken; import org.springframework.security.providers.dao.AbstractUserDetailsAuthenticationProvider; import org.springframework.security.userdetails.UserDetails; import org.springframework.security.userdetails.UsernameNotFoundException; import java.util.List; import java.util.Set; import static org.apache.commons.lang.StringUtils.isNotBlank; public class PluginAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider { private final Logger LOGGER = LoggerFactory.getLogger(getClass()); private AuthenticationPluginRegistry authenticationPluginRegistry; private AuthenticationExtension authenticationExtension; private final AuthorizationExtension authorizationExtension; private final AuthorizationMetadataStore store; private final AuthorityGranter authorityGranter; private GoConfigService configService; private PluginRoleService pluginRoleService; private UserService userService; @Autowired public PluginAuthenticationProvider(AuthenticationPluginRegistry authenticationPluginRegistry, AuthenticationExtension authenticationExtension, AuthorizationExtension authorizationExtension, AuthorityGranter authorityGranter, GoConfigService configService, PluginRoleService pluginRoleService, UserService userService) { this.authenticationPluginRegistry = authenticationPluginRegistry; this.authenticationExtension = authenticationExtension; this.authorizationExtension = authorizationExtension; this.store = AuthorizationMetadataStore.instance(); this.authorityGranter = authorityGranter; this.configService = configService; this.pluginRoleService = pluginRoleService; this.userService = userService; } @Override protected void additionalAuthenticationChecks(UserDetails userDetails, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { } @Override protected UserDetails retrieveUser(String username, UsernamePasswordAuthenticationToken authentication) throws AuthenticationException { User user = getUserDetailsFromAuthorizationPlugins(username, authentication); if (user == null) { user = getUserDetailsFromAuthenticationPlugins(username, authentication); } if (user == null) { removeAnyAssociatedPluginRolesFor(username); throw new UsernameNotFoundException("Unable to authenticate user: " + username); } userService.addUserIfDoesNotExist(toDomainUser(user)); GoUserPrinciple goUserPrinciple = getGoUserPrinciple(user); return goUserPrinciple; } private com.thoughtworks.go.domain.User toDomainUser(User user) { return new com.thoughtworks.go.domain.User(user.getUsername(),user.getDisplayName(),user.getEmailId()); } private void removeAnyAssociatedPluginRolesFor(String username) { pluginRoleService.revokeAllRolesFor(username); } private User getUserDetailsFromAuthenticationPlugins(String username, UsernamePasswordAuthenticationToken authentication) { Set<String> plugins = authenticationPluginRegistry.getPluginsThatSupportsPasswordBasedAuthentication(); for (String pluginId : plugins) { String password = (String) authentication.getCredentials(); User user = ensureDisplayNamePresent(authenticationExtension.authenticateUser(pluginId, username, password)); if (user != null) { return user; } } return null; } private User getUserDetailsFromAuthorizationPlugins(String username, UsernamePasswordAuthenticationToken authentication) { Set<AuthorizationPluginInfo> plugins = store.getPluginsThatSupportsPasswordBasedAuthentication(); for (AuthorizationPluginInfo pluginInfo : plugins) { String password = (String) authentication.getCredentials(); List<SecurityAuthConfig> authConfigs = configService.security().securityAuthConfigs().findByPluginId(pluginInfo.getDescriptor().id()); final List<PluginRoleConfig> roleConfigs = configService.security().getPluginRoles(pluginInfo.getDescriptor().id()); if (authConfigs == null || authConfigs.isEmpty()) continue; AuthenticationResponse response = authorizationExtension.authenticateUser(pluginInfo.getDescriptor().id(), username, password, authConfigs, roleConfigs); User user = ensureDisplayNamePresent(response.getUser()); if (user != null) { pluginRoleService.updatePluginRoles(pluginInfo.getDescriptor().id(), username, CaseInsensitiveString.caseInsensitiveStrings(response.getRoles())); return user; } } return null; } private GoUserPrinciple getGoUserPrinciple(User user) { return new GoUserPrinciple(user.getUsername(), user.getDisplayName(), "", true, true, true, true, authorityGranter.authorities(user.getUsername())); } @Override public boolean supports(Class authentication) { if (store.getPluginsThatSupportsPasswordBasedAuthentication().size() > 0) { return super.supports(authentication); } if (authenticationPluginRegistry.getPluginsThatSupportsPasswordBasedAuthentication().size() > 0) { return super.supports(authentication); } return false; } private User ensureDisplayNamePresent(User user) { if (user == null) { return null; } if (isNotBlank(user.getDisplayName())) { return user; } return new User(user.getUsername(), user.getUsername(), user.getEmailId()); } }