org.cloudfoundry.identity.uaa.scim.endpoints.PasswordResetEndpoints.java Source code

Java tutorial

Introduction

Here is the source code for org.cloudfoundry.identity.uaa.scim.endpoints.PasswordResetEndpoints.java

Source

/*******************************************************************************
 *     Cloud Foundry 
 *     Copyright (c) [2009-2014] Pivotal Software, Inc. All Rights Reserved.
 *
 *     This product is licensed to you under the Apache License, Version 2.0 (the "License").
 *     You may not use this product except in compliance with the License.
 *
 *     This product includes a number of subcomponents with
 *     separate copyright notices and license terms. Your use of these
 *     subcomponents is subject to the terms and conditions of the
 *     subcomponent's license, as noted in the LICENSE file.
 *******************************************************************************/
package org.cloudfoundry.identity.uaa.scim.endpoints;

import static org.springframework.http.HttpStatus.BAD_REQUEST;
import static org.springframework.http.HttpStatus.CREATED;
import static org.springframework.http.HttpStatus.INTERNAL_SERVER_ERROR;
import static org.springframework.http.HttpStatus.OK;
import static org.springframework.http.HttpStatus.UNAUTHORIZED;

import org.cloudfoundry.identity.uaa.codestore.ExpiringCode;
import org.cloudfoundry.identity.uaa.codestore.ExpiringCodeStore;
import org.cloudfoundry.identity.uaa.password.event.PasswordChangeEvent;
import org.cloudfoundry.identity.uaa.password.event.PasswordChangeFailureEvent;
import org.cloudfoundry.identity.uaa.password.event.ResetPasswordRequestEvent;
import org.cloudfoundry.identity.uaa.scim.ScimUser;
import org.cloudfoundry.identity.uaa.scim.ScimUserProvisioning;
import org.cloudfoundry.identity.uaa.scim.exception.ScimResourceNotFoundException;
import org.cloudfoundry.identity.uaa.user.UaaUser;
import org.codehaus.jackson.annotate.JsonProperty;
import org.springframework.context.ApplicationEvent;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;

import java.sql.Timestamp;
import java.util.Date;
import java.util.List;

@Controller
public class PasswordResetEndpoints implements ApplicationEventPublisherAware {

    public static final int PASSWORD_RESET_LIFETIME = 30 * 60 * 1000;
    private final ScimUserProvisioning scimUserProvisioning;
    private final ExpiringCodeStore expiringCodeStore;
    private ApplicationEventPublisher publisher;

    public PasswordResetEndpoints(ScimUserProvisioning scimUserProvisioning, ExpiringCodeStore expiringCodeStore) {
        this.scimUserProvisioning = scimUserProvisioning;
        this.expiringCodeStore = expiringCodeStore;
    }

    @Override
    public void setApplicationEventPublisher(ApplicationEventPublisher publisher) {
        this.publisher = publisher;
    }

    @RequestMapping(value = "/password_resets", method = RequestMethod.POST)
    public ResponseEntity<String> resetPassword(@RequestBody String email) {
        List<ScimUser> results = scimUserProvisioning.query("email eq '" + email + "'");
        if (results.isEmpty()) {
            return new ResponseEntity<String>(BAD_REQUEST);
        }
        ScimUser scimUser = results.get(0);
        String code = expiringCodeStore
                .generateCode(scimUser.getId(), new Timestamp(System.currentTimeMillis() + PASSWORD_RESET_LIFETIME))
                .getCode();
        publish(new ResetPasswordRequestEvent(email, code, SecurityContextHolder.getContext().getAuthentication()));
        return new ResponseEntity<String>(code, CREATED);
    }

    @RequestMapping(value = "/password_change", method = RequestMethod.POST)
    public ResponseEntity<String> changePassword(@RequestBody PasswordChange passwordChange) {
        ResponseEntity<String> responseEntity;
        if (isCodeAuthenticatedChange(passwordChange)) {
            responseEntity = changePasswordCodeAuthenticated(passwordChange);
        } else if (isUsernamePasswordAuthenticatedChange(passwordChange)) {
            responseEntity = changePasswordUsernamePasswordAuthenticated(passwordChange);
        } else {
            responseEntity = new ResponseEntity<String>(BAD_REQUEST);
        }
        return responseEntity;
    }

    private boolean isUsernamePasswordAuthenticatedChange(PasswordChange passwordChange) {
        return passwordChange.getUsername() != null && passwordChange.getCurrentPassword() != null
                && passwordChange.getCode() == null;
    }

    private boolean isCodeAuthenticatedChange(PasswordChange passwordChange) {
        return passwordChange.getCode() != null && passwordChange.getCurrentPassword() == null
                && passwordChange.getUsername() == null;
    }

    private ResponseEntity<String> changePasswordUsernamePasswordAuthenticated(PasswordChange passwordChange) {
        List<ScimUser> results = scimUserProvisioning.query("userName eq '" + passwordChange.getUsername() + "'");
        if (results.isEmpty()) {
            return new ResponseEntity<String>(BAD_REQUEST);
        }
        String oldPassword = passwordChange.getCurrentPassword();
        ScimUser user = results.get(0);
        try {
            scimUserProvisioning.changePassword(user.getId(), oldPassword, passwordChange.getNewPassword());
            publish(new PasswordChangeEvent("Password changed", getUaaUser(user),
                    SecurityContextHolder.getContext().getAuthentication()));
            return new ResponseEntity<String>(user.getUserName(), OK);
        } catch (BadCredentialsException x) {
            publish(new PasswordChangeFailureEvent(x.getMessage(), getUaaUser(user),
                    SecurityContextHolder.getContext().getAuthentication()));
            return new ResponseEntity<String>(UNAUTHORIZED);
        } catch (ScimResourceNotFoundException x) {
            publish(new PasswordChangeFailureEvent(x.getMessage(), getUaaUser(user),
                    SecurityContextHolder.getContext().getAuthentication()));
            return new ResponseEntity<String>(HttpStatus.NOT_FOUND);
        } catch (Exception x) {
            publish(new PasswordChangeFailureEvent(x.getMessage(), getUaaUser(user),
                    SecurityContextHolder.getContext().getAuthentication()));
            return new ResponseEntity<String>(INTERNAL_SERVER_ERROR);
        }
    }

    private ResponseEntity<String> changePasswordCodeAuthenticated(PasswordChange passwordChange) {
        ExpiringCode expiringCode = expiringCodeStore.retrieveCode(passwordChange.getCode());
        if (expiringCode == null) {
            return new ResponseEntity<String>(BAD_REQUEST);
        }
        String userId = expiringCode.getData();
        ScimUser user = scimUserProvisioning.retrieve(userId);
        try {
            scimUserProvisioning.changePassword(userId, null, passwordChange.getNewPassword());
            publish(new PasswordChangeEvent("Password changed", getUaaUser(user),
                    SecurityContextHolder.getContext().getAuthentication()));
            return new ResponseEntity<String>(user.getUserName(), OK);
        } catch (BadCredentialsException x) {
            publish(new PasswordChangeFailureEvent(x.getMessage(), getUaaUser(user),
                    SecurityContextHolder.getContext().getAuthentication()));
            return new ResponseEntity<String>(UNAUTHORIZED);
        } catch (ScimResourceNotFoundException x) {
            publish(new PasswordChangeFailureEvent(x.getMessage(), getUaaUser(user),
                    SecurityContextHolder.getContext().getAuthentication()));
            return new ResponseEntity<String>(HttpStatus.NOT_FOUND);
        } catch (Exception x) {
            publish(new PasswordChangeFailureEvent(x.getMessage(), getUaaUser(user),
                    SecurityContextHolder.getContext().getAuthentication()));
            return new ResponseEntity<String>(INTERNAL_SERVER_ERROR);
        }
    }

    private UaaUser getUaaUser(ScimUser scimUser) {
        Date today = new Date();
        return new UaaUser(scimUser.getId(), scimUser.getUserName(), "N/A", scimUser.getPrimaryEmail(), null,
                scimUser.getGivenName(), scimUser.getFamilyName(), today, today);
    }

    public static class PasswordChange {
        @JsonProperty("username")
        private String username;

        @JsonProperty("code")
        private String code;

        @JsonProperty("current_password")
        private String currentPassword;

        @JsonProperty("new_password")
        private String newPassword;

        public String getUsername() {
            return username;
        }

        public void setUsername(String username) {
            this.username = username;
        }

        public String getCode() {
            return code;
        }

        public void setCode(String code) {
            this.code = code;
        }

        public String getCurrentPassword() {
            return currentPassword;
        }

        public void setCurrentPassword(String currentPassword) {
            this.currentPassword = currentPassword;
        }

        public String getNewPassword() {
            return newPassword;
        }

        public void setNewPassword(String newPassword) {
            this.newPassword = newPassword;
        }
    }

    protected void publish(ApplicationEvent event) {
        if (publisher != null) {
            publisher.publishEvent(event);
        }
    }
}