blob: ae9e7246e0271de21ebc5136dfda3c3770b70a3f [file] [log] [blame]
/*
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.qpid.server.security.auth.manager.oauth2.cloudfoundry;
import static java.nio.charset.StandardCharsets.UTF_8;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URI;
import java.net.URL;
import java.security.GeneralSecurityException;
import java.security.Principal;
import java.util.Base64;
import java.util.Collections;
import java.util.Map;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.qpid.server.configuration.IllegalConfigurationException;
import org.apache.qpid.server.model.NamedAddressSpace;
import org.apache.qpid.server.model.TrustStore;
import org.apache.qpid.server.plugin.PluggableService;
import org.apache.qpid.server.security.auth.UsernamePrincipal;
import org.apache.qpid.server.security.auth.manager.oauth2.IdentityResolverException;
import org.apache.qpid.server.security.auth.manager.oauth2.OAuth2AuthenticationProvider;
import org.apache.qpid.server.security.auth.manager.oauth2.OAuth2IdentityResolverService;
import org.apache.qpid.server.security.auth.manager.oauth2.OAuth2Utils;
import org.apache.qpid.server.util.ConnectionBuilder;
import org.apache.qpid.server.util.ServerScopedRuntimeException;
@PluggableService
public class CloudFoundryOAuth2IdentityResolverService implements OAuth2IdentityResolverService
{
private static final Logger LOGGER = LoggerFactory.getLogger(CloudFoundryOAuth2IdentityResolverService.class);
public static final String TYPE = "CloudFoundryIdentityResolver";
private final ObjectMapper _objectMapper = new ObjectMapper();
@Override
public String getType()
{
return TYPE;
}
@Override
public void validate(final OAuth2AuthenticationProvider<?> authProvider) throws IllegalConfigurationException
{
}
@Override
public Principal getUserPrincipal(final OAuth2AuthenticationProvider<?> authenticationProvider,
final String accessToken,
final NamedAddressSpace addressSpace) throws IOException, IdentityResolverException
{
URL checkTokenEndpoint = authenticationProvider.getIdentityResolverEndpointURI(addressSpace).toURL();
TrustStore trustStore = authenticationProvider.getTrustStore();
String clientId = authenticationProvider.getClientId();
String clientSecret = authenticationProvider.getClientSecret();
ConnectionBuilder connectionBuilder = new ConnectionBuilder(checkTokenEndpoint);
connectionBuilder.setConnectTimeout(authenticationProvider.getConnectTimeout())
.setReadTimeout(authenticationProvider.getReadTimeout());
if (trustStore != null)
{
try
{
connectionBuilder.setTrustMangers(trustStore.getTrustManagers());
}
catch (GeneralSecurityException e)
{
throw new ServerScopedRuntimeException("Cannot initialise TLS", e);
}
}
connectionBuilder.setTlsProtocolWhiteList(authenticationProvider.getTlsProtocolWhiteList())
.setTlsProtocolBlackList(authenticationProvider.getTlsProtocolBlackList())
.setTlsCipherSuiteWhiteList(authenticationProvider.getTlsCipherSuiteWhiteList())
.setTlsCipherSuiteBlackList(authenticationProvider.getTlsCipherSuiteBlackList());
LOGGER.debug("About to call identity service '{}'", checkTokenEndpoint);
HttpURLConnection connection = connectionBuilder.build();
connection.setDoOutput(true); // makes sure to use POST
connection.setRequestProperty("Accept-Charset", UTF_8.name());
connection.setRequestProperty("Content-Type", "application/x-www-form-urlencoded;charset=" + UTF_8.name());
connection.setRequestProperty("Accept", "application/json");
String encoded = Base64.getEncoder().encodeToString((clientId + ":" + clientSecret).getBytes(UTF_8));
connection.setRequestProperty("Authorization", "Basic " + encoded);
final Map<String,String> requestParameters = Collections.singletonMap("token", accessToken);
connection.connect();
try (OutputStream output = connection.getOutputStream())
{
output.write(OAuth2Utils.buildRequestQuery(requestParameters).getBytes(UTF_8));
output.close();
try (InputStream input = OAuth2Utils.getResponseStream(connection))
{
int responseCode = connection.getResponseCode();
LOGGER.debug("Call to identity service '{}' complete, response code : {}", checkTokenEndpoint, responseCode);
Map<String, String> responseMap = null;
try
{
responseMap = _objectMapper.readValue(input, Map.class);
}
catch (JsonProcessingException e)
{
throw new IOException(String.format("Identity resolver '%s' did not return json", checkTokenEndpoint), e);
}
if (responseCode != 200)
{
throw new IdentityResolverException(String.format("Identity resolver '%s' failed, response code %d, error '%s', description '%s'",
checkTokenEndpoint,
responseCode,
responseMap.get("error"),
responseMap.get("error_description")));
}
final String userName = responseMap.get("user_name");
if (userName == null)
{
throw new IdentityResolverException(String.format("Identity resolver '%s' failed, response did not include 'user_name'",
checkTokenEndpoint));
}
return new UsernamePrincipal(userName, authenticationProvider);
}
}
}
@Override
public URI getDefaultAuthorizationEndpointURI(final OAuth2AuthenticationProvider<?> oAuth2AuthenticationProvider)
{
return null;
}
@Override
public URI getDefaultTokenEndpointURI(final OAuth2AuthenticationProvider<?> oAuth2AuthenticationProvider)
{
return null;
}
@Override
public URI getDefaultIdentityResolverEndpointURI(final OAuth2AuthenticationProvider<?> oAuth2AuthenticationProvider)
{
return null;
}
@Override
public String getDefaultScope(final OAuth2AuthenticationProvider<?> oAuth2AuthenticationProvider)
{
return "";
}
}