Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
628 views
in Technique[技术] by (71.8m points)

authentication - Issue with custom Authorization in DropWizard

I am trying to add custom authorization in dropwizard but not able to successed.

I have a custom authentication added for dropwizard by binding it to authFactory

Authenticator ssoAuthenticator = createSSOAuthenticator(configuration.getSsoGrantClientConfiguration());
environment.jersey().register(AuthFactory.binder(
                    new SSOTokenAuthFactory<SSOGrant>(
                                       ssoAuthenticator,
                                          SYSTEM_PREFIX,
                                         SSOGrant.class))
 );

and adding a dynamicfeature for authorization

environment.jersey().register(PermissionDynamicFeature.class);

Below is the annotation created

@Documented
@Retention(java.lang.annotation.RetentionPolicy.RUNTIME)
@Target({ElementType.PARAMETER,java.lang.annotation.ElementType.TYPE, java.lang.annotation.ElementType.METHOD})
public @interface PermissionsAllowed {
    String[] value();
}

I am checking whether the annotation is present on the method and then registering a filter

public class PermissionDynamicFeature implements DynamicFeature {
@Override
    public void configure(final ResourceInfo resourceInfo, final FeatureContext configuration) {

        final AnnotatedMethod am = new AnnotatedMethod(resourceInfo.getResourceMethod());
        final Annotation[][] parameterAnnotations = am.getParameterAnnotations();
            for (Annotation[] annotations : parameterAnnotations) {
                for (Annotation annotation : annotations) {
                    if (annotation instanceof PermissionsAllowed) {
                        configuration.register(new RolesAllowedRequestFilter(((PermissionsAllowed)annotation).value()));
                        return;
                    }
                }
            }
        }



    //@Priority(Priorities.USER) // authorization filter - should go after any authentication filters
    private static class RolesAllowedRequestFilter implements ContainerRequestFilter {

        private final boolean denyAll;
        private final String[] rolesAllowed;

        RolesAllowedRequestFilter() {
            this.denyAll = true;
            this.rolesAllowed = null;
        }

        RolesAllowedRequestFilter(final String[] rolesAllowed) {
            this.denyAll = false;
            this.rolesAllowed = (rolesAllowed != null) ? rolesAllowed : new String[] {};
        }

        @Override
        public void filter(final ContainerRequestContext requestContext) throws IOException {
            if (!denyAll) {
                if (rolesAllowed.length > 0 && !isAuthenticated(requestContext)) {
                    throw new ForbiddenException(LocalizationMessages.USER_NOT_AUTHORIZED());
                }

                for (final String role : rolesAllowed) {
                    if (requestContext.getSecurityContext().isUserInRole(role)) {
                        return;
                    }
                }
            }

            throw new ForbiddenException(LocalizationMessages.USER_NOT_AUTHORIZED());
        }

        private static boolean isAuthenticated(final ContainerRequestContext requestContext) {
            return requestContext.getSecurityContext().getUserPrincipal() != null;
        }
    }
}

I am just trying to build my authorization based on the same lines as RolesAllowed filter.

The issue that i am facing is that the Authorization filter is called before the authentication. What i am missing so that the authentication happens first and the authorization filter is called later?

The same happens when we register RolesAllowedDynamicFeature

environment.jersey().register(RolesAllowedDynamicFeature.class);

RolesAllowedDynamicFeature is called even before the authentication happens.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

so based on your answers I wrote up a test and I believe I can tell you what's the issue here.

The Authfactory you are using to provide Authentication tokens is not a request Filter. based on the documentation of jersey, this is the execution order of a request:

https://jersey.java.net/documentation/latest/filters-and-interceptors.html#d0e9976

The issue is the following:

ALL request filter will always be executed before your binding is executed. At the time of the request, jersey doesn't even know if it needs to bind anything to your method at all. Why should it create anything, a filter might reject the request before it gets to execution.

So in short, annotating your resource method with @Auth simply adds an injection binder to your jersey environment. You can read about custom injection here:

https://jersey.java.net/documentation/latest/ioc.html

This obviously works correctly and is quite handy, however not what you want. What you want is to reject a request before it passed through any filter. For this you MUST write a request filter. Annotate it with the correct priority and everything should be working fine.

You could have a think about extracting your auth logic into a common class (Which you already did) and then register the same class with a RequestFilter and your Authenticator, therefore keeping the Auth provider, while still having request filtering based on Authentication.

run(...) {

   myAuthStuff = create()
   jersey.register(MyAuthRequstFilter(myAuthStuff));
   jersey.register(MyAuthInjectionBinder(myAuthStuff));

}

Add a cache and you won't have to worry about calling the same thing twice.

I believe dropwizard did not intend this to work with filters. It appears their intention was to inject the auth context into a resource method and do authentication etc in there. Not my preferred solution, but it could work.

So to sum stuff up:

What you want to do is not supported by dropwizard out of the box. The solution is to extend their solution into a request filter.

Hope that helps,

Artur


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...