-
Notifications
You must be signed in to change notification settings - Fork 7
Authorization feature and bearer #43
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from 3 commits
Commits
Show all changes
5 commits
Select commit
Hold shift + click to select a range
f4f791f
Add AuthorizationSecurityFeature, BearerAuthenticator and refactor ex…
amanteaux b919980
Merge remote-tracking branch 'origin/master' into authorization-featu…
amanteaux 8785d56
Add readme
amanteaux c80cd41
Review internal naming
amanteaux 5cd3c01
Fix unit tests: forbidden exception no long set messages
amanteaux File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
69 changes: 69 additions & 0 deletions
69
...b-jersey/src/main/java/com/coreoz/plume/jersey/security/AuthorizationSecurityFeature.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
package com.coreoz.plume.jersey.security; | ||
|
||
import jakarta.ws.rs.container.ContainerRequestContext; | ||
import jakarta.ws.rs.container.ContainerRequestFilter; | ||
import jakarta.ws.rs.container.DynamicFeature; | ||
import jakarta.ws.rs.container.ResourceInfo; | ||
import jakarta.ws.rs.core.FeatureContext; | ||
import lombok.extern.slf4j.Slf4j; | ||
|
||
import java.lang.annotation.Annotation; | ||
import java.lang.reflect.AnnotatedElement; | ||
|
||
/** | ||
* Provide a general way of implementing a Jersey request authentication filter | ||
* that will be active on a method or a class depending on the presence of an annotation.<br> | ||
* <br> | ||
* The priority will be:<br> | ||
* 1. If the annotation is present on the resource method, then this annotation will be used when calling the {@link AuthorizationVerifier}<br> | ||
* 2. Else if the annotation is present on the resource class, then this annotation will be used when calling the {@link AuthorizationVerifier}<br> | ||
* 3. Else the authentication filter will not be active for the whole resource | ||
* @param <A> The annotation type that will be looked to on the resource to enable the authentication filter | ||
* @see com.coreoz.plume.jersey.security.basic.BasicAuthenticator | ||
* @see com.coreoz.plume.jersey.security.bearer.BearerAuthenticator | ||
* @see com.coreoz.plume.jersey.security.permission.PermissionFeature | ||
*/ | ||
@Slf4j | ||
public class AuthorizationSecurityFeature<A extends Annotation> implements DynamicFeature { | ||
private final Class<A> restrictedAnnotations; | ||
private final AuthorizationVerifier<A> authorizationVerifier; | ||
|
||
/** | ||
* @param restrictedAnnotations The annotation type that will hold the authentication | ||
* @param authorizationVerifier The function that will verify that the request is authorized, else it should throw {@link jakarta.ws.rs.ForbiddenException} or {@link jakarta.ws.rs.ClientErrorException} | ||
*/ | ||
public AuthorizationSecurityFeature(Class<A> restrictedAnnotations, AuthorizationVerifier<A> authorizationVerifier) { | ||
this.restrictedAnnotations = restrictedAnnotations; | ||
this.authorizationVerifier = authorizationVerifier; | ||
} | ||
|
||
@Override | ||
public void configure(ResourceInfo methodResourceInfo, FeatureContext methodResourceContext) { | ||
A methodAnnotation = fetchAnnotation(methodResourceInfo.getResourceMethod()); | ||
if (methodAnnotation != null) { | ||
methodResourceContext.register(new AuthorizationFilter(methodAnnotation)); | ||
} else { | ||
A classAnnotation = fetchAnnotation(methodResourceInfo.getResourceClass()); | ||
if (classAnnotation != null) { | ||
methodResourceContext.register(new AuthorizationFilter(classAnnotation)); | ||
} | ||
} | ||
} | ||
|
||
private A fetchAnnotation(AnnotatedElement annotatedElement) { | ||
return annotatedElement.getAnnotation(restrictedAnnotations); | ||
} | ||
|
||
private class AuthorizationFilter implements ContainerRequestFilter { | ||
private final A authorizationAnnotation; | ||
|
||
public AuthorizationFilter(A authorizationAnnotation) { | ||
this.authorizationAnnotation = authorizationAnnotation; | ||
} | ||
|
||
@Override | ||
public void filter(ContainerRequestContext requestContext) { | ||
authorizationVerifier.verifyAuthentication(authorizationAnnotation, requestContext); | ||
} | ||
} | ||
} |
27 changes: 27 additions & 0 deletions
27
plume-web-jersey/src/main/java/com/coreoz/plume/jersey/security/AuthorizationVerifier.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
package com.coreoz.plume.jersey.security; | ||
|
||
import jakarta.ws.rs.ClientErrorException; | ||
import jakarta.ws.rs.ForbiddenException; | ||
import jakarta.ws.rs.container.ContainerRequestContext; | ||
|
||
import javax.annotation.Nonnull; | ||
import java.lang.annotation.Annotation; | ||
|
||
/** | ||
* The function that will verify that an incoming request is authorized or not<br> | ||
* <br> | ||
* This function should be used within the {@link AuthorizationSecurityFeature}. | ||
* @param <A> The annotation type used to identify that the verifier should be applied on a resource method/class | ||
*/ | ||
@FunctionalInterface | ||
public interface AuthorizationVerifier<A extends Annotation> { | ||
/** | ||
* Verify that an incoming request is authorized | ||
* | ||
* @param authorizationAnnotation The annotation type used to identify that the verifier should be applied on a resource method/class | ||
* @param requestContext The request context that should be used to verify the authorization | ||
* @throws ForbiddenException If the user cannot access the resource | ||
* @throws ClientErrorException If there is another error about the request authorization | ||
*/ | ||
void verifyAuthentication(@Nonnull A authorizationAnnotation, @Nonnull ContainerRequestContext requestContext) throws ForbiddenException, ClientErrorException; | ||
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
19 changes: 19 additions & 0 deletions
19
plume-web-jersey/src/main/java/com/coreoz/plume/jersey/security/basic/BasicRestricted.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.coreoz.plume.jersey.security.basic; | ||
|
||
import java.lang.annotation.Documented; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.Target; | ||
|
||
import static java.lang.annotation.ElementType.METHOD; | ||
import static java.lang.annotation.ElementType.TYPE; | ||
import static java.lang.annotation.RetentionPolicy.RUNTIME; | ||
|
||
/** | ||
* An annotation that can be used to set up an {@link com.coreoz.plume.jersey.security.AuthorizationSecurityFeature} | ||
* with a {@link BasicAuthenticator} | ||
*/ | ||
@Documented | ||
@Retention(RUNTIME) | ||
@Target({TYPE, METHOD}) | ||
public @interface BasicRestricted { | ||
} |
62 changes: 62 additions & 0 deletions
62
...web-jersey/src/main/java/com/coreoz/plume/jersey/security/bearer/BearerAuthenticator.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
package com.coreoz.plume.jersey.security.bearer; | ||
|
||
import com.coreoz.plume.jersey.security.AuthorizationSecurityFeature; | ||
import com.google.common.net.HttpHeaders; | ||
import jakarta.ws.rs.ForbiddenException; | ||
import jakarta.ws.rs.container.ContainerRequestContext; | ||
import lombok.extern.slf4j.Slf4j; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
import java.lang.annotation.Annotation; | ||
import java.security.MessageDigest; | ||
|
||
/** | ||
* Provide a generic resource authenticator for API-key based resource authorization | ||
*/ | ||
@Slf4j | ||
public class BearerAuthenticator { | ||
private static final String BEARER_PREFIX = "Bearer "; | ||
|
||
private final String authenticationSecretHeader; | ||
|
||
public BearerAuthenticator(String bearerToken) { | ||
this.authenticationSecretHeader = BEARER_PREFIX + bearerToken; | ||
} | ||
|
||
/** | ||
* Provide a {@link AuthorizationSecurityFeature} from the bearer authenticator that can be used in Jersey | ||
* to provide authentication on annotated resources. | ||
* @param bearerAnnotation The annotation that will be used to identify resources that must be authorized. For example {@link BearerRestricted} can be used if it is not already used in the project for another authorization system | ||
* @return The corresponding {@link AuthorizationSecurityFeature} | ||
* @param <A> The annotation type used to identify required bearer authenticated resources | ||
*/ | ||
public <A extends Annotation> AuthorizationSecurityFeature<A> toAuthorizationFeature(Class<A> bearerAnnotation) { | ||
return new AuthorizationSecurityFeature<>( | ||
bearerAnnotation, | ||
(authorizationAnnotation, requestContext) -> verifyAuthentication(requestContext) | ||
); | ||
} | ||
|
||
public void verifyAuthentication(@NotNull ContainerRequestContext requestContext) { | ||
String bearer = parseBearerHeader(requestContext.getHeaderString(HttpHeaders.AUTHORIZATION)); | ||
|
||
if (bearer == null || !MessageDigest.isEqual(authenticationSecretHeader.getBytes(), bearer.getBytes())) { | ||
logger.warn("Invalid bearer header: {}", bearer); | ||
throw new ForbiddenException(); | ||
} | ||
} | ||
|
||
public static String parseBearerHeader(String authorizationHeader) { | ||
if(authorizationHeader == null) { | ||
logger.debug("Missing Authorization header"); | ||
return null; | ||
} | ||
|
||
if(!authorizationHeader.startsWith(BEARER_PREFIX)) { | ||
logger.debug("Bearer Authorization header must starts with '{}'", BEARER_PREFIX); | ||
return null; | ||
} | ||
|
||
return authorizationHeader; | ||
} | ||
} |
19 changes: 19 additions & 0 deletions
19
plume-web-jersey/src/main/java/com/coreoz/plume/jersey/security/bearer/BearerRestricted.java
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
package com.coreoz.plume.jersey.security.bearer; | ||
|
||
import java.lang.annotation.Documented; | ||
import java.lang.annotation.Retention; | ||
import java.lang.annotation.Target; | ||
|
||
import static java.lang.annotation.ElementType.METHOD; | ||
import static java.lang.annotation.ElementType.TYPE; | ||
import static java.lang.annotation.RetentionPolicy.RUNTIME; | ||
|
||
/** | ||
* An annotation that can be used to set up an {@link com.coreoz.plume.jersey.security.AuthorizationSecurityFeature} | ||
* with a {@link BearerAuthenticator} | ||
*/ | ||
@Documented | ||
@Retention(RUNTIME) | ||
@Target({TYPE, METHOD}) | ||
public @interface BearerRestricted { | ||
} |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.