001/* 002 * SonarQube 003 * Copyright (C) 2009-2018 SonarSource SA 004 * mailto:info AT sonarsource DOT com 005 * 006 * This program is free software; you can redistribute it and/or 007 * modify it under the terms of the GNU Lesser General Public 008 * License as published by the Free Software Foundation; either 009 * version 3 of the License, or (at your option) any later version. 010 * 011 * This program is distributed in the hope that it will be useful, 012 * but WITHOUT ANY WARRANTY; without even the implied warranty of 013 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 014 * Lesser General Public License for more details. 015 * 016 * You should have received a copy of the GNU Lesser General Public License 017 * along with this program; if not, write to the Free Software Foundation, 018 * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. 019 */ 020package org.sonar.api.server.authentication; 021 022import java.util.HashSet; 023import java.util.Set; 024import javax.annotation.CheckForNull; 025import javax.annotation.Nullable; 026import javax.annotation.concurrent.Immutable; 027import org.sonar.api.user.UserGroupValidation; 028 029import static com.google.common.base.Preconditions.checkArgument; 030import static java.util.Objects.requireNonNull; 031import static org.apache.commons.lang.StringUtils.isNotBlank; 032 033/** 034 * User information provided by the Identity Provider to be register into the platform. 035 * 036 * @since 5.4 037 */ 038@Immutable 039public final class UserIdentity { 040 041 private final String providerLogin; 042 private final String login; 043 private final String name; 044 private final String email; 045 private final boolean groupsProvided; 046 private final Set<String> groups; 047 048 private UserIdentity(Builder builder) { 049 this.providerLogin = builder.providerLogin; 050 this.login = builder.login; 051 this.name = builder.name; 052 this.email = builder.email; 053 this.groupsProvided = builder.groupsProvided; 054 this.groups = builder.groups; 055 } 056 057 /** 058 * Non-blank user login for the related {@link IdentityProvider}. 059 */ 060 public String getProviderLogin() { 061 return providerLogin; 062 } 063 064 /** 065 * Non-blank user login, unique for the SonarQube platform. 066 * If two {@link IdentityProvider} define two users with the same login, then users are considered as identical. 067 */ 068 public String getLogin() { 069 return login; 070 } 071 072 /** 073 * Non-blank display name. Uniqueness is not mandatory, even it's recommended for easier search of users 074 * in webapp. 075 */ 076 public String getName() { 077 return name; 078 } 079 080 /** 081 * Optional non-blank email. If defined, then it must be unique among all the users defined by all 082 * {@link IdentityProvider}. If not unique, then authentication will fail. 083 */ 084 @CheckForNull 085 public String getEmail() { 086 return email; 087 } 088 089 /** 090 * Return true if groups should be synchronized for this user. 091 * 092 * @since 5.5 093 */ 094 public boolean shouldSyncGroups() { 095 return groupsProvided; 096 } 097 098 /** 099 * List of group membership of the user. Only existing groups in SonarQube will be synchronized. 100 * 101 * @since 5.5 102 */ 103 public Set<String> getGroups() { 104 return groups; 105 } 106 107 public static Builder builder() { 108 return new Builder(); 109 } 110 111 public static class Builder { 112 private String providerLogin; 113 private String login; 114 private String name; 115 private String email; 116 private boolean groupsProvided = false; 117 private Set<String> groups = new HashSet<>(); 118 119 private Builder() { 120 } 121 122 /** 123 * @see UserIdentity#getProviderLogin() 124 */ 125 public Builder setProviderLogin(String providerLogin) { 126 this.providerLogin = providerLogin; 127 return this; 128 } 129 130 /** 131 * @see UserIdentity#getLogin() () 132 */ 133 public Builder setLogin(String login) { 134 this.login = login; 135 return this; 136 } 137 138 /** 139 * @see UserIdentity#getName() 140 */ 141 public Builder setName(String name) { 142 this.name = name; 143 return this; 144 } 145 146 /** 147 * @see UserIdentity#getEmail() 148 */ 149 public Builder setEmail(@Nullable String email) { 150 this.email = email; 151 return this; 152 } 153 154 /** 155 * Set group membership of the user. This method should only be used when synchronization of groups should be done. 156 * <ul> 157 * <li>When groups are not empty, group membership is synchronized when user logs in : 158 * <ul> 159 * <li>User won't belong anymore to a group that is not in the list (even the default group defined in 'sonar-users')</li> 160 * <li>User will belong only to groups that exist in SonarQube</li> 161 * <li>Groups that don't exist in SonarQube are silently ignored</li> 162 * </ul> 163 * <li>When groups are empty, user won't belong to any group</li> 164 * </ul> 165 * 166 * @throws NullPointerException when groups is null 167 * @since 5.5 168 */ 169 public Builder setGroups(Set<String> groups) { 170 requireNonNull(groups, "Groups cannot be null, please don't use this method if groups should not be synchronized."); 171 groups.forEach(UserGroupValidation::validateGroupName); 172 this.groupsProvided = true; 173 this.groups = groups; 174 return this; 175 } 176 177 public UserIdentity build() { 178 validateProviderLogin(providerLogin); 179 validateLogin(login); 180 validateName(name); 181 validateEmail(email); 182 return new UserIdentity(this); 183 } 184 185 private static void validateProviderLogin(String providerLogin) { 186 checkArgument(isNotBlank(providerLogin), "Provider login must not be blank"); 187 checkArgument(providerLogin.length() <= 255, "Provider login size is incorrect (maximum 255 characters)"); 188 } 189 190 private static void validateLogin(String login) { 191 checkArgument(isNotBlank(login), "User login must not be blank"); 192 checkArgument(login.length() <= 255 && login.length() >= 2, "User login size is incorrect (Between 2 and 255 characters)"); 193 } 194 195 private static void validateName(String name) { 196 checkArgument(isNotBlank(name), "User name must not be blank"); 197 checkArgument(name.length() <= 200, "User name size is too big (200 characters max)"); 198 } 199 200 private static void validateEmail(@Nullable String email) { 201 checkArgument(email == null || email.length() <= 100, "User email size is too big (100 characters max)"); 202 } 203 } 204}