org.cloudfoundry.identity.uaa.authentication.manager.RestAuthenticationManager.java Source code

Java tutorial

Introduction

Here is the source code for org.cloudfoundry.identity.uaa.authentication.manager.RestAuthenticationManager.java

Source

/*
 * ******************************************************************************
 *      Cloud Foundry
 *      Copyright (c) [2009-2016] 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.authentication.manager;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cloudfoundry.identity.uaa.user.UaaAuthority;
import org.cloudfoundry.identity.uaa.util.LinkedMaskingMultiValueMap;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.util.MultiValueMap;
import org.springframework.web.client.DefaultResponseErrorHandler;
import org.springframework.web.client.RestOperations;
import org.springframework.web.client.RestTemplate;

import java.util.Arrays;
import java.util.Map;

/**
 * An authentication manager that can be used to login to a remote UAA service
 * with username and password credentials,
 * without the local server needing to know anything about the user accounts.
 * The request is handled by the UAA's
 * RemoteAuhenticationEndpoint and success or failure is determined by the
 * response code.
 *
 * @author Dave Syer
 * @author Luke Taylor
 *
 */
public class RestAuthenticationManager implements AuthenticationManager {

    protected final Log logger = LogFactory.getLog(getClass());

    private RestOperations restTemplate = new RestTemplate();

    private static String DEFAULT_LOGIN_URL = "http://uaa.cloudfoundry.com/authenticate";

    private String remoteUrl = DEFAULT_LOGIN_URL;

    private boolean nullPassword = false;

    /**
     * @param remoteUrl the login url to set
     */
    public void setRemoteUrl(String remoteUrl) {
        this.remoteUrl = remoteUrl;
    }

    public String getRemoteUrl() {
        return remoteUrl;
    }

    /**
     * @param restTemplate a rest template to use
     */
    public void setRestTemplate(RestOperations restTemplate) {
        this.restTemplate = restTemplate;
    }

    public RestOperations getRestTemplate() {
        return restTemplate;
    }

    public RestAuthenticationManager() {
        RestTemplate restTemplate = new RestTemplate();
        // The default java.net client doesn't allow you to handle 4xx responses
        restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory());
        restTemplate.setErrorHandler(new DefaultResponseErrorHandler() {
            @Override
            protected boolean hasError(HttpStatus statusCode) {
                return statusCode.series() == HttpStatus.Series.SERVER_ERROR;
            }
        });
        this.restTemplate = restTemplate;
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        String username = authentication.getName();
        String password = (String) authentication.getCredentials();

        HttpHeaders headers = getHeaders();

        @SuppressWarnings("rawtypes")
        ResponseEntity<Map> response = restTemplate.exchange(remoteUrl, HttpMethod.POST,
                new HttpEntity<Object>(getParameters(username, password), headers), Map.class);

        if (response.getStatusCode() == HttpStatus.OK || response.getStatusCode() == HttpStatus.CREATED) {
            if (evaluateResponse(authentication, response)) {
                logger.info("Successful authentication request for " + authentication.getName());
                //TODO - we can return a UAA principal containing the correct origin here.
                return new UsernamePasswordAuthenticationToken(username, nullPassword ? null : "",
                        UaaAuthority.USER_AUTHORITIES);
            }
        } else if (response.getStatusCode() == HttpStatus.UNAUTHORIZED) {
            logger.info("Failed authentication request");
            throw new BadCredentialsException("Authentication failed");
        } else if (response.getStatusCode() == HttpStatus.INTERNAL_SERVER_ERROR) {
            logger.info("Internal error from UAA. Please Check the UAA logs.");
        } else {
            logger.error("Unexpected status code " + response.getStatusCode() + " from the UAA."
                    + " Is a compatible version running?");
        }
        throw new RuntimeException("Could not authenticate with remote server");
    }

    protected boolean evaluateResponse(Authentication authentication, ResponseEntity<Map> response) {
        String userFromUaa = (String) response.getBody().get("username");
        if (userFromUaa.equals(authentication.getPrincipal().toString())) {
            return true;
        } else {
            return false;
        }
    }

    protected Object getParameters(String username, String password) {
        MultiValueMap<String, Object> parameters = new LinkedMaskingMultiValueMap<String, Object>("password");
        parameters.set("username", username);
        parameters.set("password", password);
        return parameters;
    }

    protected HttpHeaders getHeaders() {
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
        headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
        return headers;
    }

    public boolean isNullPassword() {
        return nullPassword;
    }

    public void setNullPassword(boolean nullPassword) {
        this.nullPassword = nullPassword;
    }
}