4 votes

Comment récupérer les scopes à partir d'un jeton OAuth dans Spring boot SSO + zuul

J'essaie de créer une passerelle API simple en utilisant Spring boot SSO + Zuul. J'ai besoin de traduire les scopes OAuth en en-têtes qui seront ensuite utilisés par un autre service backend pour faire du RBAC basé sur les en-têtes.

J'utilise ce CustomOAuth2TokenRelayFilter qui va essentiellement définir les en-têtes avant l'envoi au backend. Mon problème est de savoir comment obtenir les scopes à partir du jeton actuel. La classe OAuth2AuthenticationDetails fournit la valeur du token mais pas les scopes.

Je ne suis pas sûr de la façon d'obtenir les scopes là-dedans.

Vous trouverez ci-dessous le filtre Zuul personnalisé qui est principalement tiré de https://github.com/spring-cloud/spring-cloud-security/blob/master/spring-cloud-security/src/main/java/org/springframework/cloud/security/oauth2/proxy/OAuth2TokenRelayFilter.java

    import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.stereotype.Component;

@Component
    public class CustomOAuth2TokenRelayFilter extends ZuulFilter {

        private static Logger LOGGER = LoggerFactory.getLogger(CustomOAuth2TokenRelayFilter.class);

        private static final String ACCESS_TOKEN = "ACCESS_TOKEN";
        private static final String TOKEN_TYPE = "TOKEN_TYPE";

        private OAuth2RestOperations restTemplate;

        public void setRestTemplate(OAuth2RestOperations restTemplate) {
            this.restTemplate = restTemplate;
        }

        @Override
        public int filterOrder() {
            return 1;
        }

        @Override
        public String filterType() {
            return "pre";
        }

        @Override
        public boolean shouldFilter() {
            Authentication auth = SecurityContextHolder.getContext().getAuthentication();

            if (auth instanceof OAuth2Authentication) {
                Object details = auth.getDetails();
                if (details instanceof OAuth2AuthenticationDetails) {
                    OAuth2AuthenticationDetails oauth = (OAuth2AuthenticationDetails) details;
                    RequestContext ctx = RequestContext.getCurrentContext();

                    LOGGER.debug ("role " + auth.getAuthorities());

                    LOGGER.debug("scope", ctx.get("scope")); // How do I obtain the scope ??

                    ctx.set(ACCESS_TOKEN, oauth.getTokenValue());
                    ctx.set(TOKEN_TYPE, oauth.getTokenType()==null ? "Bearer" : oauth.getTokenType());
                    return true;
                }
            }
            return false;
        }

        @Override
        public Object run() {
            RequestContext ctx = RequestContext.getCurrentContext();
            ctx.addZuulRequestHeader("x-pp-user", ctx.get(TOKEN_TYPE) + " " + getAccessToken(ctx));
            return null;
        }

        private String getAccessToken(RequestContext ctx) {
            String value = (String) ctx.get(ACCESS_TOKEN);
            if (restTemplate != null) {
                // In case it needs to be refreshed
                OAuth2Authentication auth = (OAuth2Authentication) SecurityContextHolder
                        .getContext().getAuthentication();
                if (restTemplate.getResource().getClientId()
                        .equals(auth.getOAuth2Request().getClientId())) {
                    try {
                        value = restTemplate.getAccessToken().getValue();
                    }
                    catch (Exception e) {
                        // Quite possibly a UserRedirectRequiredException, but the caller
                        // probably doesn't know how to handle it, otherwise they wouldn't be
                        // using this filter, so we rethrow as an authentication exception
                        throw new BadCredentialsException("Cannot obtain valid access token");
                    }
                }
            }
            return value;
        }

    }

11voto

Riccardo Lippolis Points 132

Vous pourriez injecter le OAuth2ClientContext dans votre filtre, et utilisez oAuth2ClientContext.getAccessToken().getScope() pour récupérer les scopes.

OAuth2ClientContext est un bean de session contenant le jeton d'accès actuel et l'état préservé.

Donc, si nous appliquons cela à votre exemple, cela ressemblerait à ceci :

import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.client.OAuth2ClientContext;
import org.springframework.security.oauth2.client.OAuth2RestOperations;
import org.springframework.security.oauth2.provider.OAuth2Authentication;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.stereotype.Component;

@Component
public class CustomOAuth2TokenRelayFilter extends ZuulFilter {

    private static Logger LOGGER = LoggerFactory.getLogger(CustomOAuth2TokenRelayFilter.class);

    private static final String ACCESS_TOKEN = "ACCESS_TOKEN";
    private static final String TOKEN_TYPE = "TOKEN_TYPE";

    private OAuth2RestOperations restTemplate;

    @Autowired
    private OAuth2ClientContext oAuth2ClientContext;

    public void setRestTemplate(OAuth2RestOperations restTemplate) {
        this.restTemplate = restTemplate;
    }

    @Override
    public int filterOrder() {
        return 1;
    }

    @Override
    public String filterType() {
        return "pre";
    }

    @Override
    public boolean shouldFilter() {
        Authentication auth = SecurityContextHolder.getContext().getAuthentication();

        if (auth instanceof OAuth2Authentication) {
            Object details = auth.getDetails();
            if (details instanceof OAuth2AuthenticationDetails) {
                OAuth2AuthenticationDetails oauth = (OAuth2AuthenticationDetails) details;
                RequestContext ctx = RequestContext.getCurrentContext();

                LOGGER.debug ("role " + auth.getAuthorities());

                LOGGER.debug("scope" + oAuth2ClientContext.getAccessToken().getScope());

                ctx.set(ACCESS_TOKEN, oauth.getTokenValue());
                ctx.set(TOKEN_TYPE, oauth.getTokenType()==null ? "Bearer" : oauth.getTokenType());
                return true;
            }
        }
        return false;
    }

    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        ctx.addZuulRequestHeader("x-pp-user", ctx.get(TOKEN_TYPE) + " " + getAccessToken(ctx));
        return null;
    }

    private String getAccessToken(RequestContext ctx) {
        String value = (String) ctx.get(ACCESS_TOKEN);
        if (restTemplate != null) {
            // In case it needs to be refreshed
            OAuth2Authentication auth = (OAuth2Authentication) SecurityContextHolder
                    .getContext().getAuthentication();
            if (restTemplate.getResource().getClientId()
                    .equals(auth.getOAuth2Request().getClientId())) {
                try {
                    value = restTemplate.getAccessToken().getValue();
                }
                catch (Exception e) {
                    // Quite possibly a UserRedirectRequiredException, but the caller
                    // probably doesn't know how to handle it, otherwise they wouldn't be
                    // using this filter, so we rethrow as an authentication exception
                    throw new BadCredentialsException("Cannot obtain valid access token");
                }
            }
        }
        return value;
    }

}

3voto

sandkeks Points 111

Vous pouvez récupérer les scopes à partir du jeton OAuth2 avec SecurityContextHolder y OAuth2Authentication

private static Set<String> getOAuthTokenScopes() {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    OAuth2Authentication oAuth2Authentication;

    if (authentication instanceof OAuth2Authentication) {
        oAuth2Authentication = (OAuth2Authentication) authentication;
    } else {
        throw new IllegalStateException("Authentication not supported!");
    }

    return oAuth2Authentication.getOAuth2Request().getScope();
}

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X