/* * Copyright 2015 McEvoy Software Ltd. * * 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 io.milton.http.http11.auth; import io.milton.common.Utils; import io.milton.http.OAuth2TokenResponse; import io.milton.http.Request; import io.milton.http.exceptions.BadRequestException; import io.milton.http.values.Pair; import io.milton.resource.OAuth2Resource.OAuth2ProfileDetails; import io.milton.resource.OAuth2Provider; import java.net.MalformedURLException; import java.net.URL; import java.util.Map; import org.apache.oltu.oauth2.client.OAuthClient; import org.apache.oltu.oauth2.client.URLConnectionClient; import org.apache.oltu.oauth2.client.request.OAuthBearerClientRequest; import org.apache.oltu.oauth2.client.request.OAuthClientRequest; import org.apache.oltu.oauth2.client.response.OAuthAccessTokenResponse; import org.apache.oltu.oauth2.client.response.OAuthJSONAccessTokenResponse; import org.apache.oltu.oauth2.client.response.OAuthResourceResponse; import org.apache.oltu.oauth2.common.OAuth; import org.apache.oltu.oauth2.common.exception.OAuthProblemException; import org.apache.oltu.oauth2.common.exception.OAuthSystemException; import org.apache.oltu.oauth2.common.message.types.GrantType; import org.apache.oltu.oauth2.common.utils.JSONUtils; import org.bouncycastle.util.encoders.Base64; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * * @author Lee YOU */ public class OAuth2Helper { private static final Logger log = LoggerFactory.getLogger(OAuth2Helper.class); public static URL getOAuth2URL(OAuth2Provider provider, String returnUrl) { log.trace("getOAuth2URL {}", provider); String oAuth2Location = provider.getAuthLocation(); String oAuth2ClientId = provider.getClientId(); String scopes = Utils.toCsv(provider.getPermissionScopes(), false); try { String state = toState(provider.getProviderId(), returnUrl); OAuthClientRequest oAuthRequest = OAuthClientRequest .authorizationLocation(oAuth2Location) .setClientId(oAuth2ClientId) .setResponseType("code") .setScope(scopes) .setState(state) .setRedirectURI(provider.getRedirectURI()) .buildQueryMessage(); return new URL(oAuthRequest.getLocationUri()); } catch (OAuthSystemException oAuthSystemException) { throw new RuntimeException(oAuthSystemException); } catch (MalformedURLException malformedURLException) { throw new RuntimeException(malformedURLException); } } public static String toState(String providerId, String returnUrl) { StringBuilder sb = new StringBuilder(providerId); if (returnUrl != null) { sb.append("||"); sb.append(returnUrl); } byte[] arr = Base64.encode(sb.toString().getBytes()); String encoded = new String(arr); return encoded; } public static Pair<String, String> parseState(String encoded) { String decoded = new String(Base64.decode(encoded)); int i = decoded.indexOf("||"); String p; String r; if (i > 0) { p = decoded.substring(0, i); r = decoded.substring(i + 2); } else { p = decoded; r = null; } return new Pair<String, String>(p, r); } private final NonceProvider nonceProvider; public OAuth2Helper(NonceProvider nonceProvider) { this.nonceProvider = nonceProvider; } // Sept 2, After Got The Authorization Code(a Access Permission), then Granting the Access Token. public OAuthAccessTokenResponse obtainAuth2Token(OAuth2Provider provider, String accessCode) throws OAuthSystemException, OAuthProblemException { log.trace("obtainAuth2Token code={}, provider={}", accessCode, provider); String oAuth2ClientId = provider.getClientId(); String oAuth2TokenLocation = provider.getTokenLocation(); String oAuth2ClientSecret = provider.getClientSecret(); String oAuth2RedirectURI = provider.getRedirectURI(); OAuthClientRequest oAuthRequest = OAuthClientRequest .tokenLocation(oAuth2TokenLocation) .setGrantType(GrantType.AUTHORIZATION_CODE) .setRedirectURI(oAuth2RedirectURI) .setCode(accessCode) .setClientId(oAuth2ClientId) .setClientSecret(oAuth2ClientSecret) .buildBodyMessage(); OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient()); // This works for facebook OAuthAccessTokenResponse oAuth2Response2 = oAuthClient.accessToken(oAuthRequest, OAuth2TokenResponse.class); //return oAuth2Response; // This might work for google OAuthJSONAccessTokenResponse o; //OAuthAccessTokenResponse oAuth2Response2 = oAuthClient.accessToken(oAuthRequest, OAuth2TokenResponse.class); return oAuth2Response2; } // Sept 3, GET the profile of the user. public OAuthResourceResponse getOAuth2Profile(OAuthAccessTokenResponse oAuth2Response, OAuth2Provider provider) throws OAuthSystemException, OAuthProblemException { log.trace("getOAuth2Profile start {}", oAuth2Response); String accessToken = oAuth2Response.getAccessToken(); String userProfileLocation = provider.getProfileLocation(); OAuthClientRequest bearerClientRequest = new OAuthBearerClientRequest(userProfileLocation) .setAccessToken(accessToken) .buildQueryMessage(); OAuthClient oAuthClient = new OAuthClient(new URLConnectionClient()); return oAuthClient.resource(bearerClientRequest, OAuth.HttpMethod.GET, OAuthResourceResponse.class); } public OAuth2ProfileDetails getOAuth2UserInfo(Request request, OAuthResourceResponse resourceResponse, OAuthAccessTokenResponse tokenResponse, OAuth2Provider prov, String oAuth2Code, String returnUrl) throws BadRequestException { log.trace(" getOAuth2UserId start..." + resourceResponse); if (resourceResponse == null) { return null; } String resourceResponseBody = resourceResponse.getBody(); log.trace(" OAuthResourceResponse, body{}" + resourceResponseBody); request.getAttributes().put(OAuth2AuthenticationHandler.REQ_ATT_OAUTH_JSON, resourceResponseBody); Map responseMap = JSONUtils.parseJSON(resourceResponseBody); String userID = (String) responseMap.get("id"); String userName = (String) responseMap.get("username"); String message = (String) responseMap.get("message"); Integer status = -1; Object errCode = responseMap.get("status"); if (errCode instanceof Integer) { status = (Integer) errCode; } else if (errCode instanceof String) { status = Integer.valueOf((String) errCode); } if (status >= 400) { throw new BadRequestException(message); } OAuth2ProfileDetails user = new OAuth2ProfileDetails(); user.setCode(oAuth2Code); user.setAccessToken(tokenResponse.getAccessToken()); user.setDetails(responseMap); user.setReturnUrl(returnUrl); if (prov != null) { user.setTokenLocation(prov.getTokenLocation()); user.setProviderId(prov.getProviderId()); } if (log.isTraceEnabled()) { log.trace(" userID{}" + userID); log.trace(" userName{}" + userName); log.trace(" oAuth2Code{}" + oAuth2Code); log.trace(" AccessToken{}" + user.getAccessToken()); log.trace("\n\n"); } return user; } }