keycloak-uncached

Merge pull request #4216 from machielg/master KEYCLOAK-5026

6/29/2017 1:52:16 AM

Details

diff --git a/core/src/main/java/org/keycloak/representations/idm/CredentialRepresentation.java b/core/src/main/java/org/keycloak/representations/idm/CredentialRepresentation.java
index d597cf3..95c7ca3 100755
--- a/core/src/main/java/org/keycloak/representations/idm/CredentialRepresentation.java
+++ b/core/src/main/java/org/keycloak/representations/idm/CredentialRepresentation.java
@@ -155,4 +155,101 @@ public class CredentialRepresentation {
     public void setConfig(MultivaluedHashMap<String, String> config) {
         this.config = config;
     }
+
+    @Override
+    public int hashCode() {
+        final int prime = 31;
+        int result = 1;
+        result = prime * result + ((algorithm == null) ? 0 : algorithm.hashCode());
+        result = prime * result + ((config == null) ? 0 : config.hashCode());
+        result = prime * result + ((counter == null) ? 0 : counter.hashCode());
+        result = prime * result + ((createdDate == null) ? 0 : createdDate.hashCode());
+        result = prime * result + ((device == null) ? 0 : device.hashCode());
+        result = prime * result + ((digits == null) ? 0 : digits.hashCode());
+        result = prime * result + ((hashIterations == null) ? 0 : hashIterations.hashCode());
+        result = prime * result + ((hashedSaltedValue == null) ? 0 : hashedSaltedValue.hashCode());
+        result = prime * result + ((period == null) ? 0 : period.hashCode());
+        result = prime * result + ((salt == null) ? 0 : salt.hashCode());
+        result = prime * result + ((temporary == null) ? 0 : temporary.hashCode());
+        result = prime * result + ((type == null) ? 0 : type.hashCode());
+        result = prime * result + ((value == null) ? 0 : value.hashCode());
+        return result;
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (this == obj)
+            return true;
+        if (obj == null)
+            return false;
+        if (getClass() != obj.getClass())
+            return false;
+        CredentialRepresentation other = (CredentialRepresentation) obj;
+        if (algorithm == null) {
+            if (other.algorithm != null)
+                return false;
+        } else if (!algorithm.equals(other.algorithm))
+            return false;
+        if (config == null) {
+            if (other.config != null)
+                return false;
+        } else if (!config.equals(other.config))
+            return false;
+        if (counter == null) {
+            if (other.counter != null)
+                return false;
+        } else if (!counter.equals(other.counter))
+            return false;
+        if (createdDate == null) {
+            if (other.createdDate != null)
+                return false;
+        } else if (!createdDate.equals(other.createdDate))
+            return false;
+        if (device == null) {
+            if (other.device != null)
+                return false;
+        } else if (!device.equals(other.device))
+            return false;
+        if (digits == null) {
+            if (other.digits != null)
+                return false;
+        } else if (!digits.equals(other.digits))
+            return false;
+        if (hashIterations == null) {
+            if (other.hashIterations != null)
+                return false;
+        } else if (!hashIterations.equals(other.hashIterations))
+            return false;
+        if (hashedSaltedValue == null) {
+            if (other.hashedSaltedValue != null)
+                return false;
+        } else if (!hashedSaltedValue.equals(other.hashedSaltedValue))
+            return false;
+        if (period == null) {
+            if (other.period != null)
+                return false;
+        } else if (!period.equals(other.period))
+            return false;
+        if (salt == null) {
+            if (other.salt != null)
+                return false;
+        } else if (!salt.equals(other.salt))
+            return false;
+        if (temporary == null) {
+            if (other.temporary != null)
+                return false;
+        } else if (!temporary.equals(other.temporary))
+            return false;
+        if (type == null) {
+            if (other.type != null)
+                return false;
+        } else if (!type.equals(other.type))
+            return false;
+        if (value == null) {
+            if (other.value != null)
+                return false;
+        } else if (!value.equals(other.value))
+            return false;
+        return true;
+    }
 }
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 6ed677f..c7b9945 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
@@ -52,6 +52,7 @@ import org.keycloak.models.UserSessionModel;
 import org.keycloak.models.*;
 import org.keycloak.models.utils.KeycloakModelUtils;
 import org.keycloak.models.utils.ModelToRepresentation;
+import org.keycloak.models.utils.RepresentationToModel;
 import org.keycloak.protocol.oidc.OIDCLoginProtocol;
 import org.keycloak.protocol.oidc.utils.RedirectUtils;
 import org.keycloak.provider.ProviderFactory;
@@ -162,8 +163,9 @@ public class UsersResource {
         try {
             UserModel user = session.users().addUser(realm, rep.getUsername());
             Set<String> emptySet = Collections.emptySet();
-            UserResource.updateUserFromRep(user, rep, emptySet, realm, session, false);
 
+            UserResource.updateUserFromRep(user, rep, emptySet, realm, session, false);
+            RepresentationToModel.createCredentials(rep, session, realm, user);
             adminEvent.operation(OperationType.CREATE).resourcePath(uriInfo, user.getId()).representation(rep).success();
 
             if (session.getTransactionManager().isActive()) {
diff --git a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserTest.java b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserTest.java
index 567b284..edcb938 100755
--- a/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserTest.java
+++ b/testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/admin/UserTest.java
@@ -17,6 +17,7 @@
 
 package org.keycloak.testsuite.admin;
 
+import org.apache.commons.collections.map.SingletonMap;
 import org.hamcrest.Matchers;
 import org.jboss.arquillian.drone.api.annotation.Drone;
 import org.jboss.arquillian.graphene.page.Page;
@@ -29,9 +30,14 @@ import org.keycloak.admin.client.resource.RealmResource;
 import org.keycloak.admin.client.resource.RoleMappingResource;
 import org.keycloak.admin.client.resource.UserResource;
 import org.keycloak.admin.client.resource.UsersResource;
+import org.keycloak.common.util.Base64;
+import org.keycloak.common.util.MultivaluedHashMap;
+import org.keycloak.credential.CredentialModel;
 import org.keycloak.events.admin.OperationType;
 import org.keycloak.events.admin.ResourceType;
 import org.keycloak.models.Constants;
+import org.keycloak.models.PasswordPolicy;
+import org.keycloak.models.RealmModel;
 import org.keycloak.models.UserModel;
 import org.keycloak.representations.idm.ClientRepresentation;
 import org.keycloak.representations.idm.CredentialRepresentation;
@@ -58,6 +64,8 @@ import org.keycloak.testsuite.util.RoleBuilder;
 import org.keycloak.testsuite.util.UserBuilder;
 import org.openqa.selenium.WebDriver;
 
+import com.google.common.collect.ImmutableMap;
+
 import javax.mail.MessagingException;
 import javax.mail.internet.MimeMessage;
 import javax.ws.rs.ClientErrorException;
@@ -65,12 +73,15 @@ import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.LinkedList;
 import java.util.List;
 
 import java.util.concurrent.atomic.AtomicInteger;
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertNotEquals;
+import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -169,6 +180,73 @@ public class UserTest extends AbstractAdminTest {
     }
     
     @Test
+    public void createUserWithHashedCredentials() {
+        UserRepresentation user = new UserRepresentation();
+        user.setUsername("user_creds");
+        user.setEmail("email@localhost");
+        
+        CredentialRepresentation hashedPassword = new CredentialRepresentation();
+        hashedPassword.setAlgorithm("my-algorithm");
+        hashedPassword.setCounter(11);
+        hashedPassword.setCreatedDate(1001l);
+        hashedPassword.setDevice("deviceX");
+        hashedPassword.setDigits(6);
+        hashedPassword.setHashIterations(22);
+        hashedPassword.setHashedSaltedValue("ABC");
+        hashedPassword.setPeriod(99);
+        hashedPassword.setSalt(Base64.encodeBytes("theSalt".getBytes()));
+        hashedPassword.setType(CredentialRepresentation.PASSWORD);
+        
+        user.setCredentials(Arrays.asList(hashedPassword));
+        
+        createUser(user);
+        
+        CredentialModel credentialHashed = fetchCredentials("user_creds");
+        assertNotNull("Expecting credential", credentialHashed);
+        assertEquals("my-algorithm", credentialHashed.getAlgorithm());
+        assertEquals(11, credentialHashed.getCounter());
+        assertEquals(Long.valueOf(1001), credentialHashed.getCreatedDate());
+        assertEquals("deviceX", credentialHashed.getDevice());
+        assertEquals(6, credentialHashed.getDigits());
+        assertEquals(22, credentialHashed.getHashIterations());
+        assertEquals("ABC", credentialHashed.getValue());
+        assertEquals(99, credentialHashed.getPeriod());
+        assertEquals("theSalt", new String(credentialHashed.getSalt()));
+        assertEquals(CredentialRepresentation.PASSWORD, credentialHashed.getType());
+    }
+    
+    @Test
+    public void createUserWithRawCredentials() {
+        UserRepresentation user = new UserRepresentation();
+        user.setUsername("user_rawpw");
+        user.setEmail("email.raw@localhost");
+
+        CredentialRepresentation rawPassword = new CredentialRepresentation();
+        rawPassword.setValue("ABCD");
+        rawPassword.setType(CredentialRepresentation.PASSWORD);
+        user.setCredentials(Arrays.asList(rawPassword));
+        
+        createUser(user);
+
+        CredentialModel credential = fetchCredentials("user_rawpw");
+        assertNotNull("Expecting credential", credential);
+        assertEquals(PasswordPolicy.HASH_ALGORITHM_DEFAULT, credential.getAlgorithm());
+        assertEquals(PasswordPolicy.HASH_ITERATIONS_DEFAULT, credential.getHashIterations());
+        assertNotEquals("ABCD", credential.getValue());
+        assertEquals(CredentialRepresentation.PASSWORD, credential.getType());
+    }
+    
+    private CredentialModel fetchCredentials(String username) {
+        return getTestingClient().server(REALM_NAME).fetch(session -> {
+            RealmModel realm = session.getContext().getRealm();
+            UserModel user = session.users().getUserByUsername(username, realm);
+            List<CredentialModel> storedCredentialsByType = session.userCredentialManager().getStoredCredentialsByType(realm, user, CredentialRepresentation.PASSWORD);
+            System.out.println(storedCredentialsByType.size());
+            return storedCredentialsByType.get(0);
+        }, CredentialModel.class);
+    }
+    
+    @Test
     public void createDuplicatedUser3() {
         createUser();