com.github.thorqin.webapi.oauth2.OAuthClient.java Source code

Java tutorial

Introduction

Here is the source code for com.github.thorqin.webapi.oauth2.OAuthClient.java

Source

/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package com.github.thorqin.webapi.oauth2;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.URL;
import java.net.URLEncoder;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.codec.binary.Base64;
import com.github.thorqin.webapi.utility.Serializer;

/**
 *
 * @author nuo.qin
 */
public class OAuthClient {

    /**
     * Client Get Authorization Code
     * @param authorityServerUri
     * @param clientId
     * @param redirectUri Authorization-Server will redirect user's browser to this URI with authorization-code. 
     * (optional, null means to use client pre-configurated value, but if no this configuration existed or 
     * have more than one configuration existing then must provide this parameter.)
     * @param scope Resource scope (optional, null means to default scope)
     * @param state Used to avoid cross-site request forgery (optional, can be null)
     * @return An URI which to let user's browser navigate to authorization server to obtain authority-code
     * @throws UnsupportedEncodingException 
     */
    public static String makeAuthorizationUri(String authorityServerUri, String clientId, String redirectUri,
            String scope, String state) throws UnsupportedEncodingException {
        StringBuilder result = new StringBuilder(authorityServerUri);
        if (authorityServerUri.contains("?"))
            result.append("&response_type=code");
        else
            result.append("?response_type=code");
        result.append("&client_id=").append(URLEncoder.encode(clientId, "utf-8"));
        if (redirectUri != null)
            result.append("&redirect_uri=").append(URLEncoder.encode(redirectUri, "utf-8"));
        if (scope != null)
            result.append("&scope=").append(URLEncoder.encode(scope, "utf-8"));
        if (state != null)
            result.append("&state=").append(URLEncoder.encode(state, "utf-8"));
        return result.toString();
    }

    /**
     * Redirect user's browser to authority server to obtain authorization code
     * @throws java.io.UnsupportedEncodingException
     * @see #makeAuthorizationUri
     * @see OAuthServer#getAuthorizationCodeRequest
     * @param authorityServerUri
     * @param response
     * @param clientId
     * @param redirectUri
     * @param scope
     * @param state 
     */
    public static void redirectAuthorization(HttpServletResponse response, String authorityServerUri,
            String clientId, String redirectUri, String scope, String state) throws IOException {
        response.sendRedirect(makeAuthorizationUri(authorityServerUri, clientId, redirectUri, scope, state));
    }

    public static String makeObtainAccessTokenByCode(String clientId, String clientSecret, String code,
            String redirectUri, boolean useBasicAuthentication) throws UnsupportedEncodingException {
        StringBuilder result = new StringBuilder("grant_type=authorization_code");
        result.append("&client_id=").append(URLEncoder.encode(clientId, "utf-8"));
        result.append("&code=").append(URLEncoder.encode(code, "utf-8"));
        if (redirectUri != null)
            result.append("&redirect_uri=").append(URLEncoder.encode(redirectUri, "utf-8"));
        if (!useBasicAuthentication && clientSecret != null && !clientSecret.isEmpty())
            result.append("&client_secret=").append(URLEncoder.encode(clientSecret, "utf-8"));
        return result.toString();
    }

    public static class AccessTokenResponse extends AccessToken {
        public String error;
        public String errorDescription;
        public String errorUri;
    }

    public static AccessToken obtainAccessTokenByCode(String authorityServerUri, String clientId,
            String clientSecret, String code, String redirectUri, boolean useBasicAuthentication)
            throws IOException, OAuthException {
        String rawData = makeObtainAccessTokenByCode(clientId, clientSecret, code, redirectUri,
                useBasicAuthentication);
        String type = "application/x-www-form-urlencoded";
        URL u = new URL(authorityServerUri);
        HttpURLConnection conn = (HttpURLConnection) u.openConnection();
        conn.setDoOutput(true);
        if (useBasicAuthentication) {
            String basicAuthentication = Base64.encodeBase64String((clientId + ":" + clientSecret).getBytes());
            conn.setRequestProperty("Authorization", "Basic " + basicAuthentication);
        }
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", type);
        conn.setRequestProperty("Content-Length", String.valueOf(rawData.length()));
        try (OutputStream os = conn.getOutputStream()) {
            os.write(rawData.getBytes());
        }
        try (InputStream is = conn.getInputStream(); InputStreamReader reader = new InputStreamReader(is)) {
            AccessTokenResponse token = Serializer.fromJson(reader, AccessTokenResponse.class);
            if (token.error != null) {
                throw new OAuthException(token.error, token.errorDescription, token.errorUri);
            }
            return token;
        }
    }

    private static String getHeadSubParameter(String content, String key) {
        Pattern pattern = Pattern.compile(key + "=\"(.*)\"");
        Matcher matcher = pattern.matcher(content);
        if (matcher.find()) {
            return matcher.group(1);
        } else
            return null;
    }

    public static <T> T obtainResource(String authorityServerUri, String accessToken, Class<T> type)
            throws IOException, OAuthException, ClassCastException {
        URL u = new URL(authorityServerUri);
        HttpURLConnection conn = (HttpURLConnection) u.openConnection();
        conn.setRequestProperty("Authorization", "Bearer " + accessToken);
        if (conn.getResponseCode() == 401) {
            String wwwAuth = conn.getHeaderField("WWW-Authenticate");
            if (wwwAuth == null) {
                throw new OAuthException("unauthorized_client");
            } else {
                throw new OAuthException(getHeadSubParameter(wwwAuth, "error"),
                        getHeadSubParameter(wwwAuth, "error_description"),
                        getHeadSubParameter(wwwAuth, "error_uri"));
            }
        } else if (conn.getResponseCode() == 400) {
            throw new OAuthException("invalid_request");
        } else if (conn.getResponseCode() > 401 && conn.getResponseCode() < 500) {
            throw new OAuthException("access_denied");
        } else if (conn.getResponseCode() >= 500) {
            throw new OAuthException("server_error");
        } else if (conn.getResponseCode() != 200)
            throw new OAuthException("unsupported_response_type");
        try (InputStream is = conn.getInputStream(); InputStreamReader reader = new InputStreamReader(is)) {
            T resource = Serializer.fromJson(reader, type);
            return resource;
        }
    }

    public AccessToken refreshAccessToken(String authorityServerUri, String clientId, String clientSecret,
            String refreshToken, String scope) throws IOException, OAuthException {
        String content = "grant_type=refresh_token&refresh_token=" + URLEncoder.encode(refreshToken, "utf-8");
        if (scope != null && !scope.trim().isEmpty())
            content += "&scope=" + URLEncoder.encode(scope, "utf-8");
        String type = "application/x-www-form-urlencoded";
        URL u = new URL(authorityServerUri);
        HttpURLConnection conn = (HttpURLConnection) u.openConnection();
        conn.setDoOutput(true);
        String basicAuthentication = Base64.encodeBase64String((clientId + ":" + clientSecret).getBytes());
        conn.setRequestProperty("Authorization", "Basic " + basicAuthentication);
        conn.setRequestMethod("POST");
        conn.setRequestProperty("Content-Type", type);
        conn.setRequestProperty("Content-Length", String.valueOf(content.length()));
        try (OutputStream os = conn.getOutputStream()) {
            os.write(content.getBytes());
        }
        try (InputStream is = conn.getInputStream(); InputStreamReader reader = new InputStreamReader(is)) {
            AccessTokenResponse token = Serializer.fromJson(reader, AccessTokenResponse.class);
            if (token.error != null) {
                throw new OAuthException(token.error, token.errorDescription, token.errorUri);
            }
            return token;
        }
    }
}