/*******************************************************************************
* 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.login;
import java.io.IOException;
import java.util.Map;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.cloudfoundry.identity.uaa.authentication.AuthzAuthenticationRequest;
import org.cloudfoundry.identity.uaa.authentication.UaaAuthenticationDetails;
import org.cloudfoundry.identity.uaa.authentication.UaaPrincipal;
import org.cloudfoundry.identity.uaa.client.SocialClientUserDetails;
import org.cloudfoundry.identity.uaa.codestore.ExpiringCode;
import org.codehaus.jackson.map.ObjectMapper;
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.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.web.client.RestTemplate;
/**
* @author Dave Syer
*
*/
public class AutologinAuthenticationManager implements AuthenticationManager {
private Log logger = LogFactory.getLog(getClass());
private RestTemplate authorizationTemplate;
private String uaaBaseUrl;
public String getUaaBaseUrl() {
return uaaBaseUrl;
}
public void setUaaBaseUrl(String uaaBaseUrl) {
this.uaaBaseUrl = uaaBaseUrl;
}
public RestTemplate getAuthorizationTemplate() {
return authorizationTemplate;
}
public void setAuthorizationTemplate(RestTemplate authorizationTemplate) {
this.authorizationTemplate = authorizationTemplate;
}
public ExpiringCode doRetrieveCode(String code) {
HttpHeaders requestHeaders = new HttpHeaders();
requestHeaders.add("Accept", MediaType.APPLICATION_JSON_VALUE);
HttpEntity<ExpiringCode> requestEntity = new HttpEntity<ExpiringCode>(null, requestHeaders);
ResponseEntity<ExpiringCode> response = authorizationTemplate.exchange(getUaaBaseUrl() + "/Codes/" + code,
HttpMethod.GET,
requestEntity, ExpiringCode.class);
if (response.getStatusCode().equals(HttpStatus.NOT_FOUND)) {
return null;
} else if (response.getStatusCode() != HttpStatus.OK) {
logger.warn("Request failed: " + requestEntity);
// TODO throw exception with the correct error
throw new RuntimeException(String.valueOf(response.getStatusCode()));
}
return response.getBody();
}
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (!(authentication instanceof AuthzAuthenticationRequest)) {
return null;
}
AuthzAuthenticationRequest request = (AuthzAuthenticationRequest) authentication;
Map<String, String> info = request.getInfo();
String code = info.get("code");
ExpiringCode ec = doRetrieveCode(code);
SocialClientUserDetails user = null;
try {
if (ec != null) {
user = new ObjectMapper().readValue(ec.getData(), SocialClientUserDetails.class);
}
} catch (IOException x) {
throw new BadCredentialsException("JsonConversion error", x);
}
if (user == null) {
throw new BadCredentialsException("Cannot redeem provided code for user");
}
// ensure that we stored clientId
String clientId = null;
String origin = null;
String userId = null;
Object principal = user.getUsername();
if (user.getDetails() instanceof String) {
clientId = (String) user.getDetails();
} else if (user.getDetails() instanceof Map) {
Map<String,String> map = (Map<String,String>)user.getDetails();
clientId = map.get("client_id");
origin = map.get("origin");
userId = map.get("user_id");
principal = new UaaPrincipal(userId,user.getUsername(),null,origin,null);
}
if (clientId == null) {
throw new BadCredentialsException("Cannot redeem provided code for user, client id missing");
}
// validate the client Id
if (!(authentication.getDetails() instanceof UaaAuthenticationDetails)) {
throw new BadCredentialsException("Cannot redeem provided code for user, auth details missing");
}
UaaAuthenticationDetails details = (UaaAuthenticationDetails) authentication.getDetails();
if (!clientId.equals(details.getClientId())) {
throw new BadCredentialsException("Cannot redeem provided code for user, client mismatch");
}
UsernamePasswordAuthenticationToken result = new UsernamePasswordAuthenticationToken(principal, null, user.getAuthorities());
result.setDetails(authentication.getDetails());
return result;
}
}