keycloak-uncached

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());
+    }
+
 }