/** * Copyright (C) 2015 Zalando SE (http://tech.zalando.com) * * Licensed 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.zalando.stups.tokens; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URI; import java.util.ArrayList; import java.util.Date; import java.util.List; import java.util.Map; import org.apache.http.HttpEntity; import org.apache.http.HttpHost; import org.apache.http.NameValuePair; import org.apache.http.auth.AuthScope; import org.apache.http.auth.UsernamePasswordCredentials; import org.apache.http.client.AuthCache; import org.apache.http.client.CredentialsProvider; import org.apache.http.client.config.RequestConfig; import org.apache.http.client.entity.UrlEncodedFormEntity; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.client.protocol.HttpClientContext; import org.apache.http.impl.auth.BasicScheme; import org.apache.http.impl.client.BasicAuthCache; import org.apache.http.impl.client.BasicCredentialsProvider; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.impl.client.HttpClients; import org.apache.http.message.BasicNameValuePair; import org.apache.http.util.EntityUtils; import com.fasterxml.jackson.databind.ObjectMapper; public class CloseableHttpProvider extends AbstractHttpProvider { private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper(); private final CloseableHttpClient client; private final HttpClientContext localContext; private UserCredentials userCredentials; private URI accessTokenUri; private final HttpHost host; private final RequestConfig requestConfig; //@formatter:off public CloseableHttpProvider(ClientCredentials clientCredentials, UserCredentials userCredentials, URI accessTokenUri, HttpConfig httpConfig) { this.userCredentials = userCredentials; this.accessTokenUri = accessTokenUri; requestConfig = RequestConfig.custom() .setSocketTimeout(httpConfig.getSocketTimeout()) .setConnectTimeout(httpConfig.getConnectTimeout()) .setConnectionRequestTimeout(httpConfig.getConnectionRequestTimeout()) .setStaleConnectionCheckEnabled(httpConfig.isStaleConnectionCheckEnabled()) .build(); // prepare basic auth credentials final CredentialsProvider credentialsProvider = new BasicCredentialsProvider(); credentialsProvider.setCredentials(new AuthScope(accessTokenUri.getHost(), accessTokenUri.getPort()), new UsernamePasswordCredentials(clientCredentials.getId(), clientCredentials.getSecret())); client = HttpClients.custom() .setUserAgent(USER_AGENT.get()) .useSystemProperties() .setDefaultCredentialsProvider(credentialsProvider) .build(); host = new HttpHost(accessTokenUri.getHost(), accessTokenUri.getPort(), accessTokenUri.getScheme()); // enable basic auth for the request final AuthCache authCache = new BasicAuthCache(); final BasicScheme basicAuth = new BasicScheme(); authCache.put(host, basicAuth); localContext = HttpClientContext.create(); localContext.setAuthCache(authCache); } //@formatter:on @Override public AccessToken createToken(final AccessTokenConfiguration tokenConfig) throws UnsupportedEncodingException { final List<NameValuePair> values = buildParameterList(tokenConfig); final HttpPost request = new HttpPost(accessTokenUri); request.setEntity(new UrlEncodedFormEntity(values)); request.setConfig(requestConfig); try (final CloseableHttpResponse response = client.execute(host, request, localContext)) { // success status code? final int status = response.getStatusLine().getStatusCode(); if (status < 200 || status >= 300) { throw AccessTokenEndpointException.from(response); } // get json response final HttpEntity entity = response.getEntity(); final AccessTokenResponse accessTokenResponse = OBJECT_MAPPER.readValue(EntityUtils.toByteArray(entity), AccessTokenResponse.class); // create new access token object final Date validUntil = calculateValidUntil(accessTokenResponse); return new AccessToken(accessTokenResponse.getAccessToken(), accessTokenResponse.getTokenType(), accessTokenResponse.getExpiresInSeconds(), validUntil); } catch (Throwable t) { throw new AccessTokenEndpointException(t.getMessage(), t); } } private List<NameValuePair> buildParameterList(final AccessTokenConfiguration tokenConfig) { Map<String, String> parameterList = buildParameterMap(tokenConfig, userCredentials); List<NameValuePair> nameValuePairs = new ArrayList<>(); for (Map.Entry<String, String> entry : parameterList.entrySet()) { nameValuePairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue())); } return nameValuePairs; } @Override public void close() throws IOException { client.close(); } }