keycloak-aplcache

Merge pull request #1282 from behana/master Add send-verify-email

5/28/2015 4:09:06 AM

Details

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 3472938..7d78d34 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,6 +12,7 @@ import javax.ws.rs.POST;
 import javax.ws.rs.PUT;
 import javax.ws.rs.Path;
 import javax.ws.rs.PathParam;
+import javax.ws.rs.QueryParam;
 import javax.ws.rs.Produces;
 import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
@@ -49,6 +50,18 @@ public interface UserResource {
     @Path("reset-password-email")
     public void resetPasswordEmail();
 
+    @PUT
+    @Path("reset-password-email")
+    public void resetPasswordEmail(@QueryParam("client_id") String clientId);
+
+    @PUT
+    @Path("send-verify-email")
+    public void sendVerifyEmail();
+
+    @PUT
+    @Path("send-verify-email")
+    public void sendVerifyEmail(@QueryParam("client_id") String clientId);
+
     @GET
     @Path("sessions")
     public List<UserSessionRepresentation> getUserSessions();
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 fa6b901..42f6420 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
@@ -57,6 +57,7 @@ import javax.ws.rs.core.MediaType;
 import javax.ws.rs.core.Response;
 import javax.ws.rs.core.UriBuilder;
 import javax.ws.rs.core.UriInfo;
+import javax.ws.rs.WebApplicationException;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -786,56 +787,72 @@ public class UsersResource {
             return ErrorResponse.error("User not found", Response.Status.NOT_FOUND);
         }
 
-        if (!user.isEnabled()) {
-            return ErrorResponse.error("User is disabled", Response.Status.BAD_REQUEST);
-        }
-
         if (user.getEmail() == null) {
             return ErrorResponse.error("User email missing", Response.Status.BAD_REQUEST);
         }
 
-        if(redirectUri != null && clientId == null){
-            return ErrorResponse.error("Client id missing", Response.Status.BAD_REQUEST);
-        }
+        ClientSessionModel clientSession = createClientSession(user, redirectUri, clientId);
+        ClientSessionCode accessCode = new ClientSessionCode(realm, clientSession);
+        accessCode.setAction(ClientSessionModel.Action.RECOVER_PASSWORD);
 
-        if(clientId == null){
-            clientId = Constants.ACCOUNT_MANAGEMENT_CLIENT_ID;
-        }
+        try {
+            UriBuilder builder = Urls.loginPasswordResetBuilder(uriInfo.getBaseUri());
+            builder.queryParam("key", accessCode.getCode());
 
-        ClientModel client = realm.getClientByClientId(clientId);
-        if (client == null || !client.isEnabled()) {
-            return ErrorResponse.error(clientId + " not enabled", Response.Status.INTERNAL_SERVER_ERROR);
+            String link = builder.build(realm.getName()).toString();
+            long expiration = TimeUnit.SECONDS.toMinutes(realm.getAccessCodeLifespanUserAction());
+
+            this.session.getProvider(EmailProvider.class).setRealm(realm).setUser(user).sendPasswordReset(link, expiration);
+
+            //audit.user(user).detail(Details.EMAIL, user.getEmail()).detail(Details.CODE_ID, accessCode.getCodeId()).success();
+
+            adminEvent.operation(OperationType.ACTION).resourcePath(uriInfo).success();
+
+            return Response.ok().build();
+        } catch (EmailException e) {
+            logger.error("Failed to send password reset email", e);
+            return ErrorResponse.error("Failed to send email", Response.Status.INTERNAL_SERVER_ERROR);
         }
+    }
 
-        String redirect;
-        if(redirectUri != null){
-            redirect = RedirectUtils.verifyRedirectUri(uriInfo, redirectUri, realm, client);
-            if(redirect == null){
-                return ErrorResponse.error("Invalid redirect uri.", Response.Status.BAD_REQUEST);
-            }
-        }else{
-            redirect = Urls.accountBase(uriInfo.getBaseUri()).path("/").build(realm.getName()).toString();
+    /**
+     * Send an email to the user with a link they can click to verify their email address.
+     * The redirectUri and clientId parameters are optional. The default for the
+     * redirect is the account client.
+     *
+     * @param username username (not id!)
+     * @param redirectUri redirect uri
+     * @param clientId client id
+     * @return
+     */
+    @Path("{username}/send-verify-email")
+    @PUT
+    @Consumes(MediaType.APPLICATION_JSON)
+    public Response sendVerifyEmail(@PathParam("username") String username, @QueryParam(OIDCLoginProtocol.REDIRECT_URI_PARAM) String redirectUri, @QueryParam(OIDCLoginProtocol.CLIENT_ID_PARAM) String clientId) {
+        auth.requireManage();
+
+        UserModel user = session.users().getUserByUsername(username, realm);
+        if (user == null) {
+            return ErrorResponse.error("User not found", Response.Status.NOT_FOUND);
         }
 
+        if (user.getEmail() == null) {
+            return ErrorResponse.error("User email missing", Response.Status.BAD_REQUEST);
+        }
 
-        UserSessionModel userSession = session.sessions().createUserSession(realm, user, username, clientConnection.getRemoteAddr(), "form", false, null, null);
-        //audit.session(userSession);
-        ClientSessionModel clientSession = session.sessions().createClientSession(realm, client);
-        clientSession.setAuthMethod(OIDCLoginProtocol.LOGIN_PROTOCOL);
-        clientSession.setRedirectUri(redirect);
-        clientSession.setUserSession(userSession);
+        ClientSessionModel clientSession = createClientSession(user, redirectUri, clientId);
         ClientSessionCode accessCode = new ClientSessionCode(realm, clientSession);
 
-        accessCode.setAction(ClientSessionModel.Action.RECOVER_PASSWORD);
+        accessCode.setAction(ClientSessionModel.Action.VERIFY_EMAIL);
 
         try {
-            UriBuilder builder = Urls.loginPasswordResetBuilder(uriInfo.getBaseUri());
+            UriBuilder builder = Urls.loginActionEmailVerificationBuilder(uriInfo.getBaseUri());
             builder.queryParam("key", accessCode.getCode());
 
             String link = builder.build(realm.getName()).toString();
             long expiration = TimeUnit.SECONDS.toMinutes(realm.getAccessCodeLifespanUserAction());
 
-            this.session.getProvider(EmailProvider.class).setRealm(realm).setUser(user).sendPasswordReset(link, expiration);
+            this.session.getProvider(EmailProvider.class).setRealm(realm).setUser(user).sendVerifyEmail(link, expiration);
 
             //audit.user(user).detail(Details.EMAIL, user.getEmail()).detail(Details.CODE_ID, accessCode.getCodeId()).success();
 
@@ -843,9 +860,53 @@ public class UsersResource {
 
             return Response.ok().build();
         } catch (EmailException e) {
-            logger.error("Failed to send password reset email", e);
+            logger.error("Failed to send verification email", e);
             return ErrorResponse.error("Failed to send email", Response.Status.INTERNAL_SERVER_ERROR);
         }
     }
 
+    private ClientSessionModel createClientSession(UserModel user, String redirectUri, String clientId) {
+
+        if (!user.isEnabled()) {
+            throw new WebApplicationException(
+                ErrorResponse.error("User is disabled", Response.Status.BAD_REQUEST));
+        }
+
+        if (redirectUri != null && clientId == null) {
+            throw new WebApplicationException(
+                ErrorResponse.error("Client id missing", Response.Status.BAD_REQUEST));
+        }
+
+        if (clientId == null) {
+            clientId = Constants.ACCOUNT_MANAGEMENT_CLIENT_ID;
+        }
+
+        ClientModel client = realm.getClientByClientId(clientId);
+        if (client == null || !client.isEnabled()) {
+            throw new WebApplicationException(
+                ErrorResponse.error(clientId + " not enabled", Response.Status.BAD_REQUEST));
+        }
+
+        String redirect;
+        if (redirectUri != null) {
+            redirect = RedirectUtils.verifyRedirectUri(uriInfo, redirectUri, realm, client);
+            if (redirect == null) {
+                throw new WebApplicationException(
+                    ErrorResponse.error("Invalid redirect uri.", Response.Status.BAD_REQUEST));
+            }
+        } else {
+            redirect = Urls.accountBase(uriInfo.getBaseUri()).path("/").build(realm.getName()).toString();
+        }
+
+
+        UserSessionModel userSession = session.sessions().createUserSession(realm, user, user.getUsername(), clientConnection.getRemoteAddr(), "form", false, null, null);
+        //audit.session(userSession);
+        ClientSessionModel clientSession = session.sessions().createClientSession(realm, client);
+        clientSession.setAuthMethod(OIDCLoginProtocol.LOGIN_PROTOCOL);
+        clientSession.setRedirectUri(redirect);
+        clientSession.setUserSession(userSession);
+
+        return clientSession;
+    }
+
 }
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 756b1ab..b067aee 100755
--- a/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/UserTest.java
+++ b/testsuite/integration/src/test/java/org/keycloak/testsuite/admin/UserTest.java
@@ -320,4 +320,87 @@ public class UserTest extends AbstractClientTest {
         assertNull(user1.getAttributes());
     }
 
+    @Test
+    public void sendResetPasswordEmail() {
+        UserRepresentation userRep = new UserRepresentation();
+        userRep.setUsername("user1");
+        realm.users().create(userRep);
+        UserResource user = realm.users().get("user1");
+
+        try {
+            user.resetPasswordEmail();
+            fail("Expected failure");
+        } catch (ClientErrorException e) {
+            assertEquals(400, e.getResponse().getStatus());
+
+            ErrorRepresentation error = e.getResponse().readEntity(ErrorRepresentation.class);
+            Assert.assertEquals("User email missing", error.getErrorMessage());
+        }
+        try {
+            userRep = user.toRepresentation();
+            userRep.setEmail("user1@localhost");
+            userRep.setEnabled(false);
+            user.update(userRep);
+            user.resetPasswordEmail();
+            fail("Expected failure");
+        } catch (ClientErrorException e) {
+            assertEquals(400, e.getResponse().getStatus());
+
+            ErrorRepresentation error = e.getResponse().readEntity(ErrorRepresentation.class);
+            Assert.assertEquals("User is disabled", error.getErrorMessage());
+        }
+        try {
+            userRep.setEnabled(true);
+            user.update(userRep);
+            user.resetPasswordEmail("invalidClientId");
+            fail("Expected failure");
+        } catch (ClientErrorException e) {
+            assertEquals(400, e.getResponse().getStatus());
+
+            ErrorRepresentation error = e.getResponse().readEntity(ErrorRepresentation.class);
+            Assert.assertEquals("invalidClientId not enabled", error.getErrorMessage());
+        }
+    }
+
+    @Test
+    public void sendVerifyEmail() {
+        UserRepresentation userRep = new UserRepresentation();
+        userRep.setUsername("user1");
+        realm.users().create(userRep);
+        UserResource user = realm.users().get("user1");
+
+        try {
+            user.sendVerifyEmail();
+            fail("Expected failure");
+        } catch (ClientErrorException e) {
+            assertEquals(400, e.getResponse().getStatus());
+
+            ErrorRepresentation error = e.getResponse().readEntity(ErrorRepresentation.class);
+            Assert.assertEquals("User email missing", error.getErrorMessage());
+        }
+        try {
+            userRep = user.toRepresentation();
+            userRep.setEmail("user1@localhost");
+            userRep.setEnabled(false);
+            user.update(userRep);
+            user.sendVerifyEmail();
+            fail("Expected failure");
+        } catch (ClientErrorException e) {
+            assertEquals(400, e.getResponse().getStatus());
+
+            ErrorRepresentation error = e.getResponse().readEntity(ErrorRepresentation.class);
+            Assert.assertEquals("User is disabled", error.getErrorMessage());
+        }
+        try {
+            userRep.setEnabled(true);
+            user.update(userRep);
+            user.sendVerifyEmail("invalidClientId");
+            fail("Expected failure");
+        } catch (ClientErrorException e) {
+            assertEquals(400, e.getResponse().getStatus());
+
+            ErrorRepresentation error = e.getResponse().readEntity(ErrorRepresentation.class);
+            Assert.assertEquals("invalidClientId not enabled", error.getErrorMessage());
+        }
+    }
 }