org.cloudfoundry.identity.uaa.login.SamlRemoteUaaController.java Source code

Java tutorial

Introduction

Here is the source code for org.cloudfoundry.identity.uaa.login.SamlRemoteUaaController.java

Source

/*
 * Cloud Foundry 2012.02.03 Beta
 * Copyright (c) [2009-2012] VMware, 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.login;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.security.Principal;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cloudfoundry.identity.uaa.client.SocialClientUserDetails;
import org.codehaus.jackson.map.ObjectMapper;
import org.codehaus.jackson.type.TypeReference;
import org.springframework.beans.factory.annotation.Value;
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.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.oauth2.provider.BaseClientDetails;
import org.springframework.security.providers.ExpiringUsernameAuthenticationToken;
import org.springframework.util.LinkedMultiValueMap;
import org.springframework.util.MultiValueMap;
import org.springframework.web.bind.annotation.RequestHeader;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;

public class SamlRemoteUaaController extends RemoteUaaController {

    private static final Log logger = LogFactory.getLog(SamlRemoteUaaController.class);

    private final ObjectMapper mapper = new ObjectMapper();

    @Value("${login.entityID}")
    public String entityID = "";

    @Override
    @RequestMapping(value = { "/info", "/login" }, method = RequestMethod.GET)
    public String prompts(HttpServletRequest request, @RequestHeader HttpHeaders headers, Map<String, Object> model,
            Principal principal) throws Exception {
        // Entity ID to start the discovery
        model.put("entityID", entityID);
        return super.prompts(request, headers, model, principal);
    }

    @Override
    protected Map<String, String> getLoginCredentials(Principal principal) {
        Map<String, String> login = new LinkedHashMap<String, String>();
        Collection<? extends GrantedAuthority> authorities = null;

        if (principal instanceof ExpiringUsernameAuthenticationToken) {
            appendField(login, "username",
                    ((SamlUserDetails) (((ExpiringUsernameAuthenticationToken) principal).getPrincipal()))
                            .getUsername());

            authorities = ((SamlUserDetails) (((ExpiringUsernameAuthenticationToken) principal).getPrincipal()))
                    .getAuthorities();
        } else {
            appendField(login, "username", principal.getName());
        }

        if (principal instanceof Authentication) {
            Object details = ((Authentication) principal).getPrincipal();
            if (details instanceof SocialClientUserDetails) {
                SocialClientUserDetails user = (SocialClientUserDetails) details;
                appendField(login, "name", user.getName());
                appendField(login, "external_id", user.getExternalId());
                appendField(login, "email", user.getEmail());
            }

            if (((Authentication) principal).getAuthorities() instanceof Collection<?>) {
                authorities = ((Authentication) principal).getAuthorities();
            }
        }

        if (authorities != null && authorities.size() > 0) {
            Map<String, String> externalGroupMap = new HashMap<String, String>();
            int i = 0;
            for (GrantedAuthority authority : authorities) {
                externalGroupMap.put("externalGroups." + i, authority.getAuthority());
                i++;
            }

            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            try {
                mapper.writeValue(baos, externalGroupMap);
                appendField(login, "authorities", new String(baos.toByteArray()));
            } catch (Throwable t) {
                logger.error("Unable to convert external groups to be sent for authorization ", t);
            }
        }
        return login;
    }

    @RequestMapping(value = "/oauth/token", method = RequestMethod.POST, params = "grant_type=password")
    @ResponseBody
    public ResponseEntity<byte[]> tokenEndpoint(HttpServletRequest request, HttpEntity<byte[]> entity,
            @RequestParam Map<String, String> parameters, Map<String, Object> model, Principal principal)
            throws Exception {

        // Request has a password. Owner password grant with a UAA password
        if (null != request.getParameter("password")) {
            return passthru(request, entity, model);
        } else {
            //
            MultiValueMap<String, String> requestHeadersForClientInfo = new LinkedMultiValueMap<String, String>();
            requestHeadersForClientInfo.add(AUTHORIZATION, request.getHeader(AUTHORIZATION));

            ResponseEntity<byte[]> clientInfoResponse = getDefaultTemplate().exchange(
                    getUaaBaseUrl() + "/clientinfo", HttpMethod.POST,
                    new HttpEntity<MultiValueMap<String, String>>(null, requestHeadersForClientInfo), byte[].class);

            if (clientInfoResponse.getStatusCode() == HttpStatus.OK) {
                String path = extractPath(request);

                MultiValueMap<String, String> map = new LinkedMultiValueMap<String, String>();
                map.setAll(parameters);
                if (principal != null) {
                    map.set("source", "login");
                    map.set("client_id", getClientId(clientInfoResponse.getBody()));
                    map.setAll(getLoginCredentials(principal));
                    map.remove("credentials"); // legacy vmc might break otherwise
                } else {
                    throw new BadCredentialsException("No principal found in authorize endpoint");
                }

                HttpHeaders requestHeaders = new HttpHeaders();
                requestHeaders.putAll(getRequestHeaders(requestHeaders));
                requestHeaders.remove(AUTHORIZATION.toLowerCase());
                requestHeaders.remove(ACCEPT.toLowerCase());
                requestHeaders.remove(CONTENT_TYPE.toLowerCase());
                requestHeaders.setContentType(MediaType.APPLICATION_FORM_URLENCODED);
                requestHeaders.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
                requestHeaders.remove(COOKIE);
                requestHeaders.remove(COOKIE.toLowerCase());

                ResponseEntity<byte[]> response = getAuthorizationTemplate().exchange(getUaaBaseUrl() + "/" + path,
                        HttpMethod.POST, new HttpEntity<MultiValueMap<String, String>>(map, requestHeaders),
                        byte[].class);

                saveCookie(response.getHeaders(), model);

                byte[] body = response.getBody();
                if (body != null) {
                    HttpHeaders outgoingHeaders = getResponseHeaders(response.getHeaders());
                    return new ResponseEntity<byte[]>(response.getBody(), outgoingHeaders,
                            response.getStatusCode());
                }

                throw new IllegalStateException("Neither a redirect nor a user approval");
            } else {
                throw new BadCredentialsException(new String(clientInfoResponse.getBody()));
            }
        }
    }

    private String getClientId(byte[] clientInfoResponse) {
        try {
            BaseClientDetails clientInfo = mapper.readValue(clientInfoResponse,
                    new TypeReference<BaseClientDetails>() {
                    });
            return clientInfo.getClientId();
        } catch (IOException e) {
            logger.warn("Unknown format of tokenRequest: " + new String(clientInfoResponse) + ". Ignoring.");
            return null;
        }
    }

}