All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.openshift.internal.restclient.okhttp.AuthenticatorInterceptor Maven / Gradle / Ivy

The newest version!
/******************************************************************************* 
 * Copyright (c) 2019-2020 Red Hat, Inc. 
 * Distributed under license by Red Hat, Inc. All rights reserved. 
 * This program is made available under the terms of the 
 * Eclipse Public License v1.0 which accompanies this distribution, 
 * and is available at http://www.eclipse.org/legal/epl-v10.html 
 * 
 * Contributors: 
 * Red Hat, Inc. - initial API and implementation 
 ******************************************************************************/

package com.openshift.internal.restclient.okhttp;

import java.io.IOException;
import java.net.URL;
import java.util.Map;

import org.apache.commons.lang.StringUtils;

import com.openshift.internal.restclient.AuthorizationEndpoints;
import com.openshift.internal.restclient.DefaultClient;
import com.openshift.internal.restclient.authorization.AuthorizationDetails;
import com.openshift.internal.util.URIUtils;
import com.openshift.restclient.IClient;
import com.openshift.restclient.authorization.IAuthorizationContext;
import com.openshift.restclient.authorization.IAuthorizationDetails;
import com.openshift.restclient.authorization.UnauthorizedException;
import com.openshift.restclient.http.IHttpConstants;

import okhttp3.Headers;
import okhttp3.Interceptor;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import okhttp3.Request.Builder;
import okhttp3.Response;

/**
 * Adds authorization means to every request. Authorizes and retrieves the token
 * if it's not present yet.
 */
public class AuthenticatorInterceptor implements Interceptor, IHttpConstants {

    public static final String ACCESS_TOKEN = "access_token";
    private static final String CSRF_TOKEN = "X-CSRF-Token";
    private static final String ERROR = "error";
    private static final String ERROR_DETAILS = "error_details";

    private IClient client;
    
    @Override
    public Response intercept(Chain chain) throws IOException {
        Request request = chain.request();
        String url = request.url().toString();
        if (AuthAttempHeader.isContainedIn(request.headers())
                || isUrlWithoutAuthorization(url)) {
            return chain.proceed(request);
        }
        IAuthorizationContext authorizationContext = client.getAuthorizationContext();
        if (StringUtils.isBlank(authorizationContext.getToken())) {
            request = createAuthorizationRequest(request, url, authorizationContext);
        }
        return chain.proceed(request);
    }

    private Request createAuthorizationRequest(Request request, String url, IAuthorizationContext authorizationContext) throws IOException {
        try (Response authResponse = authenticate()) {
            if (authResponse != null) {
                if (!authResponse.isSuccessful()) {
                    throw new UnauthorizedException(getAuthorizationDetails(url),
                            ResponseCodeInterceptor.getStatus(authResponse.body().string()));
                }
                String token = getToken(authResponse);
                setToken(token, client.getAuthorizationContext());
                request = new OpenShiftRequestBuilder(request.newBuilder()).acceptJson()
                        .authorization(authorizationContext)
                        .build();
            }
            return request;
        }
    }

    private boolean isUrlWithoutAuthorization(String url) {
        return url.endsWith(DefaultClient.PATH_OPENSHIFT_VERSION)
                || url.endsWith(DefaultClient.PATH_KUBERNETES_VERSION)
                || url.endsWith(DefaultClient.PATH_HEALTH_CHECK)
                || url.endsWith(AuthorizationEndpoints.PATH_OAUTH_AUTHORIZATION_SERVER)
                || isAuthorizationEndpoint(url, client.getAuthorizationEndpoint());
    }

    private boolean isAuthorizationEndpoint(String url, URL authEndpoint) {
        return authEndpoint != null
                && url.startsWith(authEndpoint.toString());
    }

    private Response authenticate() throws IOException {
        OkHttpClient okClient = client.adapt(OkHttpClient.class);
        if (okClient == null) {
            return null;
        }
        URL endpoint = client.getAuthorizationEndpoint();
        if (endpoint == null) {
            return null;
        }
        Request authRequest = appendAuthorization(
                client.getAuthorizationContext(),
                new Request.Builder()
                    .addHeader(CSRF_TOKEN, "1")
                    .url(new URL(endpoint.toExternalForm() 
                            + "?response_type=token&client_id=openshift-challenging-client").toString()));
        return okClient.newBuilder()
                .followRedirects(false)
                .build()
                .newCall(authRequest)
                .execute();
    }

    private IAuthorizationDetails getAuthorizationDetails(String url) {
        IAuthorizationDetails details = null;
        Map pairs = URIUtils.splitFragment(url);
        if (pairs.containsKey(ERROR)) {
            details = new AuthorizationDetails(pairs.get(ERROR), pairs.get(ERROR_DETAILS));
        }
        return details;
    }

    private String getToken(Response response) {
        if (response == null) {
            return null;
        }
        String token = null;
        Map pairs = URIUtils.splitFragment(response.header(PROPERTY_LOCATION));
        if (pairs.containsKey(ACCESS_TOKEN)) {
            token = pairs.get(ACCESS_TOKEN);
        }
        return token;
    }

    private void setToken(String token, IAuthorizationContext authorizationContext) {
        if (authorizationContext != null) {
            authorizationContext.setToken(token);
        }
    }

    public void setClient(IClient client) {
        this.client = client;
    }

    private Request appendAuthorization(IAuthorizationContext context, Builder builder) {
        AuthAttempHeader.add(builder);
        return new BasicChallengeHandler(context).handleChallenge(builder).build();
    }

    private static class AuthAttempHeader {

        private static final String AUTH_ATTEMPTS = "X-OPENSHIFT-AUTH-ATTEMPTS";

        public static void add(Builder builder) {
            builder.header(AUTH_ATTEMPTS, "1");    
        }

        public static boolean isContainedIn(Headers headers) {
            return headers != null
                    && headers.get(AUTH_ATTEMPTS) != null;
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy