| /* |
| * 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.olingo.fit; |
| |
| import java.io.IOException; |
| import java.net.URI; |
| |
| import javax.ws.rs.core.MediaType; |
| |
| import org.apache.commons.codec.binary.Base64; |
| import org.apache.commons.lang3.StringUtils; |
| import org.apache.cxf.jaxrs.client.JAXRSClientFactoryBean; |
| import org.apache.cxf.jaxrs.client.WebClient; |
| import org.apache.cxf.rs.security.oauth2.client.OAuthClientUtils; |
| import org.apache.cxf.rs.security.oauth2.common.ClientAccessToken; |
| import org.apache.cxf.rs.security.oauth2.grants.code.AuthorizationCodeGrant; |
| import org.apache.cxf.rs.security.oauth2.grants.refresh.RefreshTokenGrant; |
| import org.apache.cxf.rs.security.oauth2.provider.OAuthServiceException; |
| import org.apache.http.Header; |
| import org.apache.http.HttpException; |
| import org.apache.http.HttpHeaders; |
| import org.apache.http.HttpRequest; |
| import org.apache.http.HttpRequestInterceptor; |
| import org.apache.http.HttpResponse; |
| import org.apache.http.client.methods.HttpGet; |
| import org.apache.http.client.params.ClientPNames; |
| import org.apache.http.client.utils.URIBuilder; |
| import org.apache.http.impl.client.DefaultHttpClient; |
| import org.apache.http.params.BasicHttpParams; |
| import org.apache.http.params.HttpParams; |
| import org.apache.http.protocol.HttpContext; |
| import org.apache.http.util.EntityUtils; |
| import org.apache.olingo.client.core.http.AbstractOAuth2HttpClientFactory; |
| import org.apache.olingo.client.core.http.OAuth2Exception; |
| import org.apache.olingo.fit.rest.OAuth2Provider; |
| |
| import com.fasterxml.jackson.databind.JsonNode; |
| import com.fasterxml.jackson.dataformat.xml.XmlMapper; |
| |
| public class CXFOAuth2HttpClientFactory extends AbstractOAuth2HttpClientFactory { |
| |
| private static final OAuthClientUtils.Consumer OAUTH2_CONSUMER = |
| new OAuthClientUtils.Consumer(OAuth2Provider.CLIENT_ID, OAuth2Provider.CLIENT_SECRET); |
| |
| private ClientAccessToken accessToken; |
| |
| public CXFOAuth2HttpClientFactory(final URI oauth2GrantServiceURI, final URI oauth2TokenServiceURI) { |
| super(oauth2GrantServiceURI, oauth2TokenServiceURI); |
| } |
| |
| private WebClient getAccessTokenService() { |
| final JAXRSClientFactoryBean bean = new JAXRSClientFactoryBean(); |
| bean.setAddress(oauth2TokenServiceURI.toASCIIString()); |
| bean.setUsername("odatajclient"); |
| bean.setPassword("odatajclient"); |
| return bean.createWebClient(). |
| type(MediaType.APPLICATION_FORM_URLENCODED_TYPE).accept(MediaType.APPLICATION_JSON_TYPE); |
| } |
| |
| @Override |
| protected boolean isInited() throws OAuth2Exception { |
| return accessToken != null; |
| } |
| |
| @Override |
| protected void init() throws OAuth2Exception { |
| final URI authURI = OAuthClientUtils.getAuthorizationURI( |
| oauth2GrantServiceURI.toASCIIString(), |
| OAuth2Provider.CLIENT_ID, |
| OAuth2Provider.REDIRECT_URI, |
| null, |
| null); |
| |
| // Disable automatic redirects handling |
| final HttpParams params = new BasicHttpParams(); |
| params.setParameter(ClientPNames.HANDLE_REDIRECTS, false); |
| final DefaultHttpClient httpClient = new DefaultHttpClient(params); |
| |
| JsonNode oAuthAuthorizationData = null; |
| String authenticityCookie = null; |
| try { |
| // 1. Need to (basic) authenticate against the OAuth2 service |
| final HttpGet method = new HttpGet(authURI); |
| method.addHeader("Authorization", "Basic " + Base64.encodeBase64String("odatajclient:odatajclient".getBytes())); |
| final HttpResponse response = httpClient.execute(method); |
| |
| // 2. Pull out OAuth2 authorization data and "authenticity" cookie (CXF specific) |
| oAuthAuthorizationData = new XmlMapper().readTree(EntityUtils.toString(response.getEntity())); |
| |
| final Header setCookieHeader = response.getFirstHeader("Set-Cookie"); |
| if (setCookieHeader == null) { |
| throw new IllegalStateException("OAuth flow is broken"); |
| } |
| authenticityCookie = setCookieHeader.getValue(); |
| } catch (Exception e) { |
| throw new OAuth2Exception(e); |
| } |
| |
| String code = null; |
| try { |
| // 3. Submit the HTTP form for allowing access to the application |
| final URI location = new URIBuilder(oAuthAuthorizationData.get("replyTo").asText()). |
| addParameter("session_authenticity_token", oAuthAuthorizationData.get("authenticityToken").asText()). |
| addParameter("client_id", oAuthAuthorizationData.get("clientId").asText()). |
| addParameter("redirect_uri", oAuthAuthorizationData.get("redirectUri").asText()). |
| addParameter("oauthDecision", "allow"). |
| build(); |
| final HttpGet method = new HttpGet(location); |
| method.addHeader("Authorization", "Basic " + Base64.encodeBase64String("odatajclient:odatajclient".getBytes())); |
| method.addHeader("Cookie", authenticityCookie); |
| |
| final HttpResponse response = httpClient.execute(method); |
| |
| final Header locationHeader = response.getFirstHeader("Location"); |
| if (response.getStatusLine().getStatusCode() != 303 || locationHeader == null) { |
| throw new IllegalStateException("OAuth flow is broken"); |
| } |
| |
| // 4. Get the authorization code value out of this last redirect |
| code = StringUtils.substringAfterLast(locationHeader.getValue(), "="); |
| |
| EntityUtils.consumeQuietly(response.getEntity()); |
| } catch (Exception e) { |
| throw new OAuth2Exception(e); |
| } |
| |
| // 5. Obtain the access token |
| try { |
| accessToken = OAuthClientUtils.getAccessToken( |
| getAccessTokenService(), OAUTH2_CONSUMER, new AuthorizationCodeGrant(code)); |
| } catch (OAuthServiceException e) { |
| throw new OAuth2Exception(e); |
| } |
| |
| if (accessToken == null) { |
| throw new OAuth2Exception("No OAuth2 access token"); |
| } |
| } |
| |
| @Override |
| protected void accessToken(final DefaultHttpClient client) throws OAuth2Exception { |
| client.addRequestInterceptor(new HttpRequestInterceptor() { |
| |
| @Override |
| public void process(final HttpRequest request, final HttpContext context) throws HttpException, IOException { |
| request.removeHeaders(HttpHeaders.AUTHORIZATION); |
| request.addHeader(HttpHeaders.AUTHORIZATION, OAuthClientUtils.createAuthorizationHeader(accessToken)); |
| } |
| }); |
| } |
| |
| @Override |
| protected void refreshToken(final DefaultHttpClient client) throws OAuth2Exception { |
| final String refreshToken = accessToken.getRefreshToken(); |
| if (refreshToken == null) { |
| throw new OAuth2Exception("No OAuth2 refresh token"); |
| } |
| |
| // refresh the token |
| try { |
| accessToken = OAuthClientUtils.getAccessToken( |
| getAccessTokenService(), OAUTH2_CONSUMER, new RefreshTokenGrant(refreshToken)); |
| } catch (OAuthServiceException e) { |
| throw new OAuth2Exception(e); |
| } |
| } |
| |
| } |