| // Copyright (C) 2015 The Android Open Source Project |
| // |
| // 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.google.gerrit.auth.oauth; |
| |
| import static com.google.gerrit.server.account.externalids.ExternalId.SCHEME_EXTERNAL; |
| |
| import com.google.common.base.Strings; |
| import com.google.gerrit.entities.Account; |
| import com.google.gerrit.extensions.auth.oauth.OAuthLoginProvider; |
| import com.google.gerrit.extensions.auth.oauth.OAuthUserInfo; |
| import com.google.gerrit.extensions.client.AccountFieldName; |
| import com.google.gerrit.extensions.registration.DynamicMap; |
| import com.google.gerrit.server.account.AbstractRealm; |
| import com.google.gerrit.server.account.AccountException; |
| import com.google.gerrit.server.account.AccountManager; |
| import com.google.gerrit.server.account.AuthRequest; |
| import com.google.gerrit.server.account.externalids.ExternalId; |
| import com.google.gerrit.server.config.GerritServerConfig; |
| import com.google.inject.Inject; |
| import com.google.inject.Singleton; |
| import java.io.IOException; |
| import java.util.Collection; |
| import java.util.HashSet; |
| import java.util.Set; |
| import org.eclipse.jgit.lib.Config; |
| |
| @Singleton |
| public class OAuthRealm extends AbstractRealm { |
| private final DynamicMap<OAuthLoginProvider> loginProviders; |
| private final Set<AccountFieldName> editableAccountFields; |
| |
| @Inject |
| OAuthRealm(DynamicMap<OAuthLoginProvider> loginProviders, @GerritServerConfig Config config) { |
| this.loginProviders = loginProviders; |
| this.editableAccountFields = new HashSet<>(); |
| // User name should be always editable, because not all OAuth providers |
| // expose them |
| editableAccountFields.add(AccountFieldName.USER_NAME); |
| if (config.getBoolean("oauth", null, "allowEditFullName", false)) { |
| editableAccountFields.add(AccountFieldName.FULL_NAME); |
| } |
| if (config.getBoolean("oauth", null, "allowRegisterNewEmail", false)) { |
| editableAccountFields.add(AccountFieldName.REGISTER_NEW_EMAIL); |
| } |
| } |
| |
| @Override |
| public boolean allowsEdit(AccountFieldName field) { |
| return editableAccountFields.contains(field); |
| } |
| |
| /** |
| * Authenticates with the {@link OAuthLoginProvider} specified in the authentication request. |
| * |
| * <p>{@link AccountManager} calls this method without password if authenticity of the user has |
| * already been established. In that case we can skip the authentication request to the {@code |
| * OAuthLoginService}. |
| * |
| * @param who the authentication request. |
| * @return the authentication request with resolved email address and display name in case the |
| * authenticity of the user could be established; otherwise {@code who} is returned unchanged. |
| * @throws AccountException if the authentication request with the OAuth2 server failed or no |
| * {@code OAuthLoginProvider} was available to handle the request. |
| */ |
| @Override |
| public AuthRequest authenticate(AuthRequest who) throws AccountException { |
| if (Strings.isNullOrEmpty(who.getPassword())) { |
| return who; |
| } |
| |
| if (Strings.isNullOrEmpty(who.getAuthPlugin()) |
| || Strings.isNullOrEmpty(who.getAuthProvider())) { |
| throw new AccountException("Cannot authenticate"); |
| } |
| OAuthLoginProvider loginProvider = |
| loginProviders.get(who.getAuthPlugin(), who.getAuthProvider()); |
| if (loginProvider == null) { |
| throw new AccountException("Cannot authenticate"); |
| } |
| |
| OAuthUserInfo userInfo; |
| try { |
| userInfo = loginProvider.login(who.getUserName().orElse(null), who.getPassword()); |
| } catch (IOException e) { |
| throw new AccountException("Cannot authenticate", e); |
| } |
| if (userInfo == null) { |
| throw new AccountException("Cannot authenticate"); |
| } |
| if (!Strings.isNullOrEmpty(userInfo.getEmailAddress()) |
| && (!who.getUserName().isPresent() || !allowsEdit(AccountFieldName.REGISTER_NEW_EMAIL))) { |
| who.setEmailAddress(userInfo.getEmailAddress()); |
| } |
| if (!Strings.isNullOrEmpty(userInfo.getDisplayName()) |
| && (Strings.isNullOrEmpty(who.getDisplayName()) |
| || !allowsEdit(AccountFieldName.FULL_NAME))) { |
| who.setDisplayName(userInfo.getDisplayName()); |
| } |
| return who; |
| } |
| |
| @Override |
| public void onCreateAccount(AuthRequest who, Account account) {} |
| |
| @Override |
| public Account.Id lookup(String accountName) { |
| return null; |
| } |
| |
| @Override |
| public boolean accountBelongsToRealm(Collection<ExternalId> externalIds) { |
| for (ExternalId id : externalIds) { |
| if (id.isScheme(SCHEME_EXTERNAL)) { |
| return true; |
| } |
| } |
| return false; |
| } |
| } |