AbstractOAuth2Provider.java
    
    
    
    
    
        Home
            /
social                    /
core                    /
src                    /
main                    /
java                    /
org                    /
keycloak                    /
social                    /
                    AbstractOAuth2Provider.java
    
    
            
            package org.keycloak.social;
import org.json.JSONObject;
import org.keycloak.social.utils.SimpleHttp;
import java.io.IOException;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
 * @author <a href="mailto:sthorger@redhat.com">Stian Thorgersen</a>
 */
public abstract class AbstractOAuth2Provider implements SocialProvider {
    private static final String AUTHORIZATION_CODE = "authorization_code";
    private static final String ACCESS_TOKEN = "access_token";
    private static final String CLIENT_ID = "client_id";
    private static final String CLIENT_SECRET = "client_secret";
    private static final String CODE = "code";
    private static final String GRANT_TYPE = "grant_type";
    private static final String REDIRECT_URI = "redirect_uri";
    private static final String RESPONSE_TYPE = "response_type";
    private static final String SCOPE = "scope";
    private static final String STATE = "state";
    private static final String TOKEN_REGEX = "access_token=([^&]+)";
    @Override
    public abstract String getId();
    @Override
    public abstract String getName();
    protected abstract String getScope();
    protected abstract String getAuthUrl();
    protected abstract String getTokenUrl();
    protected abstract SocialUser getProfile(String accessToken) throws SocialProviderException;
    @Override
    public AuthRequest getAuthUrl(SocialProviderConfig config) throws SocialProviderException {
        String state = UUID.randomUUID().toString();
        return AuthRequest.create(state, getAuthUrl()).setQueryParam(CLIENT_ID, config.getKey())
                .setQueryParam(RESPONSE_TYPE, CODE).setQueryParam(SCOPE, getScope())
                .setQueryParam(REDIRECT_URI, config.getCallbackUrl()).setQueryParam(STATE, state).setAttribute(STATE, state).build();
    }
    @Override
    public SocialUser processCallback(SocialProviderConfig config, AuthCallback callback) throws SocialProviderException {
        String error = callback.getQueryParam("error");
        if (error != null) {
            if (error.equals("access_denied")) {
                throw new SocialAccessDeniedException();
            } else {
                throw new SocialProviderException(error);
            }
        }
        try {
            String code = callback.getQueryParam(CODE);
            if (!callback.getQueryParam(STATE).equals(callback.getAttribute(STATE))) {
                throw new SocialProviderException("Invalid state");
            }
            String response = SimpleHttp.doPost(getTokenUrl()).param(CODE, code).param(CLIENT_ID, config.getKey())
                    .param(CLIENT_SECRET, config.getSecret())
                    .param(REDIRECT_URI, config.getCallbackUrl())
                    .param(GRANT_TYPE, AUTHORIZATION_CODE).asString();
            String accessToken;
            if (response.startsWith("{")) {
                accessToken = new JSONObject(response).getString(ACCESS_TOKEN);
            } else {
                Matcher matcher = Pattern.compile(TOKEN_REGEX).matcher(response);
                if (matcher.find()) {
                    accessToken = matcher.group(1);
                } else {
                    throw new SocialProviderException("Invalid response, could not find token");
                }
            }
            return getProfile(accessToken);
        } catch (IOException e) {
            throw new SocialProviderException(e);
        }
    }
}