aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJacek <jacek.poreda@sonarsource.com>2020-12-22 16:39:32 +0100
committersonartech <sonartech@sonarsource.com>2021-01-11 20:20:38 +0000
commita915585e9181af099ee293977126dc117ffdc15a (patch)
tree03c6a6b7a5b5cb5cba0eb16a97942ba6637738a0
parent177ce9bc1e0e79ea6fb76f798ebbef7e787a6078 (diff)
downloadsonarqube-a915585e9181af099ee293977126dc117ffdc15a.tar.gz
sonarqube-a915585e9181af099ee293977126dc117ffdc15a.zip
SONAR-13930 Allow migration of auth system
-rw-r--r--server/sonar-docs/src/pages/instance-administration/delegated-auth.md3
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/UpdateIdentityProviderAction.java193
-rw-r--r--server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/UsersWsModule.java3
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/UpdateIdentityProviderActionTest.java189
-rw-r--r--server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/UsersWsModuleTest.java4
-rw-r--r--sonar-ws-generator/src/main/java/org/sonarqube/wsgenerator/ApiDefinitionDownloader.java1
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/user/UsersWsParameters.java4
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/users/UpdateIdentityProviderRequest.java72
-rw-r--r--sonar-ws/src/main/java/org/sonarqube/ws/client/users/UsersService.java17
9 files changed, 482 insertions, 4 deletions
diff --git a/server/sonar-docs/src/pages/instance-administration/delegated-auth.md b/server/sonar-docs/src/pages/instance-administration/delegated-auth.md
index c0bc8d4e6b7..f0c3ac36248 100644
--- a/server/sonar-docs/src/pages/instance-administration/delegated-auth.md
+++ b/server/sonar-docs/src/pages/instance-administration/delegated-auth.md
@@ -230,6 +230,9 @@ Authentication will be tried on each server, in the order they are listed in the
Note that all the LDAP servers must be available while (re)starting the SonarQube server.
+### Migrate users to a new authentication method
+If you are changing your delegated authentication method and migrating existing users from your previous authentication method, you can use the `api/users/update_identity_provider` web API to update your users' identity provider.
+
### Troubleshooting
* Detailed connection logs (and potential error codes received from LDAP server) are output to SonarQube's _$SONARQUBE_HOME/logs/web.log_, when logging is in `DEBUG` mode.
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/UpdateIdentityProviderAction.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/UpdateIdentityProviderAction.java
new file mode 100644
index 00000000000..e68dbf8fea3
--- /dev/null
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/UpdateIdentityProviderAction.java
@@ -0,0 +1,193 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.user.ws;
+
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+import org.sonar.api.server.authentication.IdentityProvider;
+import org.sonar.api.server.ws.Request;
+import org.sonar.api.server.ws.Response;
+import org.sonar.api.server.ws.WebService;
+import org.sonar.api.server.ws.WebService.NewController;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.user.UserDto;
+import org.sonar.server.authentication.IdentityProviderRepository;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.user.ExternalIdentity;
+import org.sonar.server.user.UpdateUser;
+import org.sonar.server.user.UserSession;
+import org.sonar.server.user.UserUpdater;
+
+import static com.google.common.base.Preconditions.checkArgument;
+import static com.google.common.base.Strings.isNullOrEmpty;
+import static java.lang.String.format;
+import static org.sonar.server.user.ExternalIdentity.SQ_AUTHORITY;
+import static org.sonarqube.ws.client.user.UsersWsParameters.ACTION_UPDATE_IDENTITY_PROVIDER;
+import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_LOGIN;
+import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_NEW_EXTERNAL_IDENTITY;
+import static org.sonarqube.ws.client.user.UsersWsParameters.PARAM_NEW_EXTERNAL_PROVIDER;
+
+public class UpdateIdentityProviderAction implements UsersWsAction {
+
+ private final DbClient dbClient;
+ private final IdentityProviderRepository identityProviderRepository;
+ private final UserUpdater userUpdater;
+ private final UserSession userSession;
+
+ public UpdateIdentityProviderAction(DbClient dbClient, IdentityProviderRepository identityProviderRepository,
+ UserUpdater userUpdater, UserSession userSession) {
+ this.dbClient = dbClient;
+ this.identityProviderRepository = identityProviderRepository;
+ this.userUpdater = userUpdater;
+ this.userSession = userSession;
+ }
+
+ @Override
+ public void define(NewController controller) {
+ WebService.NewAction action = controller.createAction(ACTION_UPDATE_IDENTITY_PROVIDER)
+ .setDescription("Update identity provider information. <br/>"
+ + "It's only possible to migrate to an installed identity provider. "
+ + "Be careful that as soon as this information has been updated for a user, "
+ + "the user will only be able to authenticate on the new identity provider. "
+ + "It is not possible to migrate external user to local one.<br/>"
+ + "Requires Administer System permission.")
+ .setSince("8.7")
+ .setInternal(false)
+ .setPost(true)
+ .setHandler(this);
+
+ action.createParam(PARAM_LOGIN)
+ .setDescription("User login")
+ .setRequired(true);
+ action.createParam(PARAM_NEW_EXTERNAL_PROVIDER)
+ .setRequired(true)
+ .setDescription("New external provider. Only authentication system installed are available. Use 'sonarqube' identity provider for LDAP.");
+
+ action.createParam(PARAM_NEW_EXTERNAL_IDENTITY)
+ .setDescription("New external identity, usually the login used in the authentication system. "
+ + "If not provided previous identity will be used.");
+ }
+
+ @Override
+ public void handle(Request request, Response response) throws Exception {
+ userSession.checkLoggedIn().checkIsSystemAdministrator();
+ UpdateIdentityProviderRequest wsRequest = toWsRequest(request);
+ doHandle(wsRequest);
+ response.noContent();
+ }
+
+ private void doHandle(UpdateIdentityProviderRequest request) {
+ checkEnabledIdentityProviders(request.newExternalProvider);
+ try (DbSession dbSession = dbClient.openSession(false)) {
+ UserDto user = getUser(dbSession, request.login);
+ ExternalIdentity externalIdentity = getExternalIdentity(request, user);
+ userUpdater.updateAndCommit(dbSession, user, new UpdateUser().setExternalIdentity(externalIdentity), u -> {
+ });
+ }
+ }
+
+ private void checkEnabledIdentityProviders(String newExternalProvider) {
+ List<String> availableIdentityProviders = getAvailableIdentityProviders();
+ checkArgument(availableIdentityProviders.contains(newExternalProvider), "Value of parameter 'newExternalProvider' (%s) must be one of: [%s]", newExternalProvider,
+ String.join(", ", availableIdentityProviders));
+ }
+
+ private List<String> getAvailableIdentityProviders() {
+ List<String> discoveredProviders = identityProviderRepository.getAllEnabledAndSorted()
+ .stream()
+ .map(IdentityProvider::getKey)
+ .collect(Collectors.toList());
+ discoveredProviders.add(SQ_AUTHORITY);
+ return discoveredProviders;
+ }
+
+ private UserDto getUser(DbSession dbSession, String login) {
+ UserDto user = dbClient.userDao().selectByLogin(dbSession, login);
+ if (user == null || !user.isActive()) {
+ throw new NotFoundException(format("User '%s' doesn't exist", login));
+ }
+ return user;
+ }
+
+ private static ExternalIdentity getExternalIdentity(UpdateIdentityProviderRequest request, UserDto user) {
+ return new ExternalIdentity(
+ request.newExternalProvider,
+ request.newExternalIdentity != null ? request.newExternalIdentity : user.getExternalLogin(),
+ null);
+ }
+
+ private static UpdateIdentityProviderRequest toWsRequest(Request request) {
+ return UpdateIdentityProviderRequest.builder()
+ .setLogin(request.mandatoryParam(PARAM_LOGIN))
+ .setNewExternalProvider(request.mandatoryParam(PARAM_NEW_EXTERNAL_PROVIDER))
+ .setNewExternalIdentity(request.param(PARAM_NEW_EXTERNAL_IDENTITY))
+ .build();
+ }
+
+ static class UpdateIdentityProviderRequest {
+ private final String login;
+ private final String newExternalProvider;
+ private final String newExternalIdentity;
+
+ public UpdateIdentityProviderRequest(Builder builder) {
+ this.login = builder.login;
+ this.newExternalProvider = builder.newExternalProvider;
+ this.newExternalIdentity = builder.newExternalIdentity;
+ }
+
+ public static UpdateIdentityProviderRequest.Builder builder() {
+ return new UpdateIdentityProviderRequest.Builder();
+ }
+
+ static class Builder {
+ private String login;
+ private String newExternalProvider;
+ private String newExternalIdentity;
+
+ private Builder() {
+ // enforce factory method use
+ }
+
+ public Builder setLogin(String login) {
+ this.login = login;
+ return this;
+ }
+
+ public Builder setNewExternalProvider(String newExternalProvider) {
+ this.newExternalProvider = newExternalProvider;
+ return this;
+ }
+
+ public Builder setNewExternalIdentity(@Nullable String newExternalIdentity) {
+ this.newExternalIdentity = newExternalIdentity;
+ return this;
+ }
+
+ public UpdateIdentityProviderRequest build() {
+ checkArgument(!isNullOrEmpty(login), "Login is mandatory and must not be empty");
+ checkArgument(!isNullOrEmpty(newExternalProvider), "New External Provider is mandatory and must not be empty");
+ return new UpdateIdentityProviderRequest(this);
+ }
+ }
+ }
+
+}
diff --git a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/UsersWsModule.java b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/UsersWsModule.java
index 23056c8079d..c7ecb05366d 100644
--- a/server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/UsersWsModule.java
+++ b/server/sonar-webserver-webapi/src/main/java/org/sonar/server/user/ws/UsersWsModule.java
@@ -46,7 +46,8 @@ public class UsersWsModule extends Module {
UserJsonWriter.class,
SetHomepageAction.class,
HomepageTypesImpl.class,
- SetSettingAction.class);
+ SetSettingAction.class,
+ UpdateIdentityProviderAction.class);
if (configuration.getBoolean(ProcessProperties.Property.SONARCLOUD_ENABLED.getKey()).orElse(false)) {
// onboarding tutorial is available only in SonarCloud
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/UpdateIdentityProviderActionTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/UpdateIdentityProviderActionTest.java
new file mode 100644
index 00000000000..59831550531
--- /dev/null
+++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/UpdateIdentityProviderActionTest.java
@@ -0,0 +1,189 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonar.server.user.ws;
+
+import org.junit.Rule;
+import org.junit.Test;
+import org.sonar.api.config.internal.MapSettings;
+import org.sonar.db.DbClient;
+import org.sonar.db.DbSession;
+import org.sonar.db.DbTester;
+import org.sonar.db.user.UserDto;
+import org.sonar.server.authentication.CredentialsLocalAuthentication;
+import org.sonar.server.authentication.IdentityProviderRepositoryRule;
+import org.sonar.server.authentication.TestIdentityProvider;
+import org.sonar.server.es.EsTester;
+import org.sonar.server.exceptions.ForbiddenException;
+import org.sonar.server.exceptions.NotFoundException;
+import org.sonar.server.exceptions.UnauthorizedException;
+import org.sonar.server.tester.UserSessionRule;
+import org.sonar.server.user.NewUserNotifier;
+import org.sonar.server.user.UserUpdater;
+import org.sonar.server.user.index.UserIndexer;
+import org.sonar.server.usergroups.DefaultGroupFinder;
+import org.sonar.server.ws.TestRequest;
+import org.sonar.server.ws.WsActionTester;
+
+import static com.google.common.collect.Lists.newArrayList;
+import static org.assertj.core.api.Assertions.assertThat;
+import static org.assertj.core.api.Assertions.assertThatThrownBy;
+import static org.mockito.Mockito.mock;
+import static org.sonar.db.user.UserTesting.newUserDto;
+
+public class UpdateIdentityProviderActionTest {
+ private final static String SQ_AUTHORITY = "sonarqube";
+
+ @Rule
+ public IdentityProviderRepositoryRule identityProviderRepository = new IdentityProviderRepositoryRule()
+ .addIdentityProvider(new TestIdentityProvider().setName("Gitlab").setKey("gitlab").setEnabled(true))
+ .addIdentityProvider(new TestIdentityProvider().setName("Github").setKey("github").setEnabled(true));
+
+ @Rule
+ public DbTester db = DbTester.create();
+ @Rule
+ public EsTester es = EsTester.create();
+ @Rule
+ public UserSessionRule userSession = UserSessionRule.standalone().logIn().setSystemAdministrator();
+
+ private final MapSettings settings = new MapSettings();
+ private final DbClient dbClient = db.getDbClient();
+ private final DbSession dbSession = db.getSession();
+ private final UserIndexer userIndexer = new UserIndexer(dbClient, es.client());
+ private final CredentialsLocalAuthentication localAuthentication = new CredentialsLocalAuthentication(dbClient);
+
+ private final WsActionTester underTest = new WsActionTester(new UpdateIdentityProviderAction(dbClient, identityProviderRepository,
+ new UserUpdater(mock(NewUserNotifier.class), dbClient, userIndexer, new DefaultGroupFinder(db.getDbClient()), settings.asConfig(), localAuthentication),
+ userSession));
+
+ @Test
+ public void change_identity_provider_of_a_local_user_all_params() {
+ String userLogin = "login-1";
+ String newExternalLogin = "login@github.com";
+ String newExternalIdentityProvider = "github";
+ createUser(true, userLogin, userLogin, SQ_AUTHORITY);
+ TestRequest request = underTest.newRequest()
+ .setParam("login", userLogin)
+ .setParam("newExternalProvider", newExternalIdentityProvider)
+ .setParam("newExternalIdentity", newExternalLogin);
+
+ request.execute();
+ assertThat(dbClient.userDao().selectByExternalLoginAndIdentityProvider(dbSession, newExternalLogin, newExternalIdentityProvider))
+ .isNotNull()
+ .extracting(UserDto::isLocal, UserDto::getExternalLogin, UserDto::getExternalIdentityProvider)
+ .contains(false, newExternalLogin, newExternalIdentityProvider);
+ }
+
+ @Test
+ public void change_identity_provider_of_a_local_user_mandatory_params_only_provider_login_stays_same() {
+ String userLogin = "login-1";
+ String newExternalIdentityProvider = "github";
+ createUser(true, userLogin, userLogin, SQ_AUTHORITY);
+ TestRequest request = underTest.newRequest()
+ .setParam("login", userLogin)
+ .setParam("newExternalProvider", newExternalIdentityProvider);
+
+ request.execute();
+ assertThat(dbClient.userDao().selectByExternalLoginAndIdentityProvider(dbSession, userLogin, newExternalIdentityProvider))
+ .isNotNull()
+ .extracting(UserDto::isLocal, UserDto::getExternalLogin, UserDto::getExternalIdentityProvider)
+ .contains(false, userLogin, newExternalIdentityProvider);
+ }
+
+ @Test
+ public void change_identity_provider_of_a_external_user_to_new_one() {
+ String userLogin = "login-1";
+ String oldExternalIdentityProvider = "gitlab";
+ String oldExternalIdentity = "john@gitlab.com";
+ createUser(false, userLogin, oldExternalIdentity, oldExternalIdentityProvider);
+
+ String newExternalIdentityProvider = "github";
+ String newExternalIdentity = "john@github.com";
+ TestRequest request = underTest.newRequest()
+ .setParam("login", userLogin)
+ .setParam("newExternalProvider", newExternalIdentityProvider)
+ .setParam("newExternalIdentity", newExternalIdentity);
+
+ request.execute();
+ assertThat(dbClient.userDao().selectByExternalLoginAndIdentityProvider(dbSession, newExternalIdentity, newExternalIdentityProvider))
+ .isNotNull()
+ .extracting(UserDto::isLocal, UserDto::getExternalLogin, UserDto::getExternalIdentityProvider)
+ .contains(false, newExternalIdentity, newExternalIdentityProvider);
+ }
+
+ @Test
+ public void fail_if_user_not_exist() {
+ TestRequest request = underTest.newRequest()
+ .setParam("login", "not-existing")
+ .setParam("newExternalProvider", "gitlab");
+
+ assertThatThrownBy(request::execute)
+ .isInstanceOf(NotFoundException.class)
+ .hasMessage("User 'not-existing' doesn't exist");
+ }
+
+ @Test
+ public void fail_if_identity_provider_not_exist() {
+ createUser(true, "login-1", "login-1", SQ_AUTHORITY);
+ TestRequest request = underTest.newRequest()
+ .setParam("login", "login-1")
+ .setParam("newExternalProvider", "not-existing");
+
+ assertThatThrownBy(request::execute)
+ .isInstanceOf(IllegalArgumentException.class)
+ .hasMessage("Value of parameter 'newExternalProvider' (not-existing) must be one of: [github, gitlab, sonarqube]");
+ }
+
+ @Test
+ public void fail_if_anonymous() {
+ userSession.anonymous();
+ TestRequest request = underTest.newRequest()
+ .setParam("login", "not-existing")
+ .setParam("newExternalProvider", "something");
+
+ assertThatThrownBy(request::execute)
+ .isInstanceOf(UnauthorizedException.class);
+ }
+
+ @Test
+ public void fail_if_not_admin() {
+ userSession.logIn("some-user");
+ TestRequest request = underTest.newRequest()
+ .setParam("login", "not-existing")
+ .setParam("newExternalProvider", "something");
+
+ assertThatThrownBy(request::execute)
+ .isInstanceOf(ForbiddenException.class);
+ }
+
+ private void createUser(boolean local, String login, String externalLogin, String externalIdentityProvider) {
+ UserDto userDto = newUserDto()
+ .setEmail("john@email.com")
+ .setLogin(login)
+ .setName("John")
+ .setScmAccounts(newArrayList("jn"))
+ .setActive(true)
+ .setLocal(local)
+ .setExternalLogin(externalLogin)
+ .setExternalIdentityProvider(externalIdentityProvider);
+ dbClient.userDao().insert(dbSession, userDto);
+ userIndexer.commitAndIndex(dbSession, userDto);
+ }
+
+}
diff --git a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/UsersWsModuleTest.java b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/UsersWsModuleTest.java
index db34976dcd2..9e961b12313 100644
--- a/server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/UsersWsModuleTest.java
+++ b/server/sonar-webserver-webapi/src/test/java/org/sonar/server/user/ws/UsersWsModuleTest.java
@@ -34,7 +34,7 @@ public class UsersWsModuleTest {
public void verify_count_of_added_components() {
ComponentContainer container = new ComponentContainer();
new UsersWsModule(new ConfigurationBridge(settings)).configure(container);
- assertThat(container.size()).isEqualTo(2 + 14);
+ assertThat(container.size()).isEqualTo(2 + 15);
}
@Test
@@ -43,6 +43,6 @@ public class UsersWsModuleTest {
ComponentContainer container = new ComponentContainer();
new UsersWsModule(new ConfigurationBridge(settings)).configure(container);
- assertThat(container.size()).isEqualTo(2 + 15);
+ assertThat(container.size()).isEqualTo(2 + 16);
}
}
diff --git a/sonar-ws-generator/src/main/java/org/sonarqube/wsgenerator/ApiDefinitionDownloader.java b/sonar-ws-generator/src/main/java/org/sonarqube/wsgenerator/ApiDefinitionDownloader.java
index 4c25869f801..b998af934dc 100644
--- a/sonar-ws-generator/src/main/java/org/sonarqube/wsgenerator/ApiDefinitionDownloader.java
+++ b/sonar-ws-generator/src/main/java/org/sonarqube/wsgenerator/ApiDefinitionDownloader.java
@@ -43,6 +43,7 @@ public class ApiDefinitionDownloader {
Orchestrator orchestrator = builder
// Enable organizations ws
.setServerProperty("sonar.sonarcloud.enabled", "true")
+ .setServerProperty("sonar.forceAuthentication", "false")
.build();
orchestrator.start();
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UsersWsParameters.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UsersWsParameters.java
index 434814810ca..fd15902dec0 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UsersWsParameters.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/user/UsersWsParameters.java
@@ -27,9 +27,9 @@ public class UsersWsParameters {
public static final String ACTION_CREATE = "create";
public static final String ACTION_DEACTIVATE = "deactivate";
public static final String ACTION_UPDATE = "update";
- public static final String ACTION_GROUPS = "groups";
public static final String ACTION_SKIP_ONBOARDING_TUTORIAL = "skip_onboarding_tutorial";
public static final String ACTION_CURRENT = "current";
+ public static final String ACTION_UPDATE_IDENTITY_PROVIDER = "update_identity_provider";
public static final String PARAM_LOGIN = "login";
public static final String PARAM_PASSWORD = "password";
@@ -40,6 +40,8 @@ public class UsersWsParameters {
public static final String PARAM_SCM_ACCOUNT = "scmAccount";
public static final String PARAM_LOCAL = "local";
public static final String PARAM_SELECTED = "selected";
+ public static final String PARAM_NEW_EXTERNAL_PROVIDER = "newExternalProvider";
+ public static final String PARAM_NEW_EXTERNAL_IDENTITY = "newExternalIdentity";
private UsersWsParameters() {
// Only static stuff
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/users/UpdateIdentityProviderRequest.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/users/UpdateIdentityProviderRequest.java
new file mode 100644
index 00000000000..31c40d1bcb4
--- /dev/null
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/users/UpdateIdentityProviderRequest.java
@@ -0,0 +1,72 @@
+/*
+ * SonarQube
+ * Copyright (C) 2009-2020 SonarSource SA
+ * mailto:info AT sonarsource DOT com
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+package org.sonarqube.ws.client.users;
+
+import java.util.List;
+import javax.annotation.Generated;
+
+/**
+ * This is part of the internal API.
+ * This is a POST request.
+ * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/users/update_identity_provider">Further information about this action online (including a response example)</a>
+ * @since 8.7
+ */
+@Generated("sonar-ws-generator")
+public class UpdateIdentityProviderRequest {
+
+ private String login;
+ private String newExternalIdentity;
+ private String newExternalProvider;
+
+ /**
+ * This is a mandatory parameter.
+ */
+ public UpdateIdentityProviderRequest setLogin(String login) {
+ this.login = login;
+ return this;
+ }
+
+ public String getLogin() {
+ return login;
+ }
+
+ /**
+ */
+ public UpdateIdentityProviderRequest setNewExternalIdentity(String newExternalIdentity) {
+ this.newExternalIdentity = newExternalIdentity;
+ return this;
+ }
+
+ public String getNewExternalIdentity() {
+ return newExternalIdentity;
+ }
+
+ /**
+ * This is a mandatory parameter.
+ */
+ public UpdateIdentityProviderRequest setNewExternalProvider(String newExternalProvider) {
+ this.newExternalProvider = newExternalProvider;
+ return this;
+ }
+
+ public String getNewExternalProvider() {
+ return newExternalProvider;
+ }
+}
diff --git a/sonar-ws/src/main/java/org/sonarqube/ws/client/users/UsersService.java b/sonar-ws/src/main/java/org/sonarqube/ws/client/users/UsersService.java
index 694d3037b5a..edcad0df8be 100644
--- a/sonar-ws/src/main/java/org/sonarqube/ws/client/users/UsersService.java
+++ b/sonar-ws/src/main/java/org/sonarqube/ws/client/users/UsersService.java
@@ -227,4 +227,21 @@ public class UsersService extends BaseService {
.setParam("newLogin", request.getNewLogin())
.setMediaType(MediaTypes.JSON)).content();
}
+
+ /**
+ *
+ * This is part of the internal API.
+ * This is a POST request.
+ * @see <a href="https://next.sonarqube.com/sonarqube/web_api/api/users/update_identity_provider">Further information about this action online (including a response example)</a>
+ * @since 8.7
+ */
+ public void updateIdentityProvider(UpdateIdentityProviderRequest request) {
+ call(
+ new PostRequest(path("update_identity_provider"))
+ .setParam("login", request.getLogin())
+ .setParam("newExternalIdentity", request.getNewExternalIdentity())
+ .setParam("newExternalProvider", request.getNewExternalProvider())
+ .setMediaType(MediaTypes.JSON)
+ ).content();
+ }
}