Details
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java
index 1c6e003..1488d38 100755
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/Keycloak.java
@@ -15,10 +15,17 @@ public class Keycloak {
private final Config config;
private final TokenManager tokenManager;
+ private final ResteasyWebTarget target;
+ private final ResteasyClient client;
private Keycloak(String serverUrl, String realm, String username, String password, String clientId, String clientSecret){
config = new Config(serverUrl, realm, username, password, clientId, clientSecret);
tokenManager = new TokenManager(config);
+
+ client = new ResteasyClientBuilder().build();
+ target = client.target(config.getServerUrl());
+
+ target.register(new BearerAuthFilter(tokenManager.getAccessTokenString()));
}
public static Keycloak getInstance(String serverUrl, String realm, String username, String password, String clientId, String clientSecret){
@@ -30,11 +37,6 @@ public class Keycloak {
}
public RealmsResource realms(){
- ResteasyClient client = new ResteasyClientBuilder().build();
- ResteasyWebTarget target = client.target(config.getServerUrl());
-
- target.register(new BearerAuthFilter(tokenManager.getAccessTokenString()));
-
return target.proxy(RealmsResource.class);
}
@@ -46,4 +48,8 @@ public class Keycloak {
return tokenManager;
}
+ public void close() {
+ client.close();
+ }
+
}
diff --git a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UserResource.java b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UserResource.java
index 70cf066..65b011f 100755
--- a/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UserResource.java
+++ b/integration/admin-client/src/main/java/org/keycloak/admin/client/resource/UserResource.java
@@ -12,8 +12,10 @@ import javax.ws.rs.GET;
import javax.ws.rs.POST;
import javax.ws.rs.PUT;
import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
import javax.ws.rs.Produces;
import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.Response;
import java.util.List;
import java.util.Map;
@@ -61,6 +63,14 @@ public interface UserResource {
@Path("social-links")
public List<SocialLinkRepresentation> getSocialLinks();
+ @POST
+ @Path("social-links/{provider}")
+ public Response addSocialLink(@PathParam("provider") String provider, SocialLinkRepresentation rep);
+
+ @Path("social-links/{provider}")
+ @DELETE
+ public void removeSocialLink(final @PathParam("provider") String provider);
+
@Path("role-mappings")
public RoleMappingResource roles();
diff --git a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
index 79584ff..b04ef18 100755
--- a/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
+++ b/services/src/main/java/org/keycloak/services/resources/admin/UsersResource.java
@@ -290,6 +290,39 @@ public class UsersResource {
return result;
}
+ @Path("{username}/social-links/{provider}")
+ @POST
+ @NoCache
+ public Response addSocialLink(final @PathParam("username") String username, final @PathParam("provider") String provider, SocialLinkRepresentation rep) {
+ auth.requireManage();
+ UserModel user = session.users().getUserByUsername(username, realm);
+ if (user == null) {
+ throw new NotFoundException("User not found");
+ }
+ if (session.users().getSocialLink(user, provider, realm) != null) {
+ return Flows.errors().exists("User is already linked with provider");
+ }
+
+ SocialLinkModel socialLink = new SocialLinkModel(provider, rep.getSocialUserId(), rep.getSocialUsername());
+ session.users().addSocialLink(realm, user, socialLink);
+
+ return Response.noContent().build();
+ }
+
+ @Path("{username}/social-links/{provider}")
+ @DELETE
+ @NoCache
+ public void removeSocialLink(final @PathParam("username") String username, final @PathParam("provider") String provider) {
+ auth.requireManage();
+ UserModel user = session.users().getUserByUsername(username, realm);
+ if (user == null) {
+ throw new NotFoundException("User not found");
+ }
+ if (!session.users().removeSocialLink(realm, user, provider)) {
+ throw new NotFoundException("Link not found");
+ }
+ }
+
/**
* Remove all user sessions associated with this user. And, for all applications that have an admin URL, tell
* them to invalidate the sessions for this particular user.
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AbstractClientTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AbstractClientTest.java
index 43b4494..9a57d39 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AbstractClientTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/AbstractClientTest.java
@@ -51,6 +51,8 @@ public abstract class AbstractClientTest {
@After
public void after() {
+ keycloak.close();
+
keycloakRule.configure(new KeycloakRule.KeycloakSetup() {
@Override
public void config(RealmManager manager, RealmModel adminstrationRealm, RealmModel appRealm) {
diff --git a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/UserTest.java b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/UserTest.java
index a25f98e..0d94657 100644
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/UserTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/UserTest.java
@@ -1,10 +1,12 @@
package org.keycloak.testsuite.admin;
import org.junit.Test;
+import org.keycloak.admin.client.resource.UserResource;
+import org.keycloak.representations.idm.SocialLinkRepresentation;
import org.keycloak.representations.idm.UserRepresentation;
import javax.ws.rs.ClientErrorException;
-
+import javax.ws.rs.core.Response;
import java.util.List;
import static org.junit.Assert.assertEquals;
@@ -108,4 +110,43 @@ public class UserTest extends AbstractClientTest {
assertEquals(9, users.size());
}
+ @Test
+ public void addSocialLink() {
+ createUser();
+
+ UserResource user = realm.users().get("user1");
+
+ SocialLinkRepresentation link = new SocialLinkRepresentation();
+ link.setSocialUserId("social-user-id");
+ link.setSocialUsername("social-username");
+
+ Response response = user.addSocialLink("social-provider-id", link);
+ assertEquals(204, response.getStatus());
+ }
+
+ @Test
+ public void getSocialLinks() {
+ addSocialLink();
+
+ UserResource user = realm.users().get("user1");
+ assertEquals(1, user.getSocialLinks().size());
+
+ SocialLinkRepresentation link = user.getSocialLinks().get(0);
+ assertEquals("social-provider-id", link.getSocialProvider());
+ assertEquals("social-user-id", link.getSocialUserId());
+ assertEquals("social-username", link.getSocialUsername());
+ }
+
+ @Test
+ public void removeSocialLink() {
+ addSocialLink();
+
+ UserResource user = realm.users().get("user1");
+ assertEquals(1, user.getSocialLinks().size());
+
+ user.removeSocialLink("social-provider-id");
+
+ assertEquals(0, user.getSocialLinks().size());
+ }
+
}