Hello Matthias,

Regarding authentication I normally use a ContainerRequestFilter.
Follows an example of a filter where authentication is done using a JWT
token.
It uses JwtService that is responsible for creating and validating tokens.
It uses jose4j.


@Secured
> @Provider
> @Priority(Priorities.AUTHENTICATION)
> @Component(scope = ServiceScope.PROTOTYPE, //
>         service = { ContainerRequestFilter.class }, //
>         property = {
>                 JaxrsWhiteboardConstants.JAX_RS_EXTENSION + "=" + true, //
>                 JaxrsWhiteboardConstants.JAX_RS_NAME + "=" +
> "TokenAuthenticationFilter", //
>                 Constants.JAX_RS_APPLICATION_SELECT, //
>         })
> public class TokenAuthenticationFilter implements ContainerRequestFilter {
>
>     private static final Logger LOGGER =
> LoggerFactory.getLogger(TokenAuthenticationFilter.class);
>
>     private static final String AUTHENTICATION_SCHEME = "Bearer";
>
>     private static final String AUTHENTICATION_SCHEME_PREFIX =
> AUTHENTICATION_SCHEME + " ";
>
>     @Reference(cardinality = ReferenceCardinality.MANDATORY)
>     JwtService jwtService;
>
>     @Context
>     private ResourceInfo resourceInfo;
>
>     @Override
>     public void filter(ContainerRequestContext requestContext) throws
> IOException {
>
>         // Get the Authorization header from the request
>         String authorizationHeader =
> requestContext.getHeaderString(HttpHeaders.AUTHORIZATION);
>         LOGGER.debug("authorizationHeader {}", authorizationHeader);
>         // Validate the Authorization header
>         if (!isTokenBasedAuthentication(authorizationHeader)) {
>             LOGGER.info("Missing auth token. Aborting");
>             abortWithUnauthorized(requestContext);
>             return;
>         }
>         // Extract the token from the Authorization header
>         final String token =
> authorizationHeader.substring(AUTHENTICATION_SCHEME_PREFIX.length());
>         try {
>             // Validate the token. An exception will be thrown if invalid
>             SubjectDetails subjectDetails =
> jwtService.validateToken(token);
>             LOGGER.debug("Token for subject {} accepted",
> subjectDetails.getId());
>             initSecurityContext(requestContext, subjectDetails);
>             Permission requiredPermission =
> getPermissionForResource(resourceInfo);
>             if (!subjectDetails.hasPermission(requiredPermission)) {
>                 LOGGER.debug("subject {} lack permission {}",
> subjectDetails.getId(), requiredPermission);
>                 abortWithForbidden(requestContext);
>             }
>         }
>         catch (AuthenticationException e) {
>             LOGGER.trace("Ignored", e);
>             LOGGER.info("Token validation failed. Aborting");
>             abortWithUnauthorized(requestContext);
>         }
>     }
>
>     /**
>      * @param requestContext
>      * @param subjectDetails
>      */
>     private void initSecurityContext(ContainerRequestContext
> requestContext, SubjectDetails subjectDetails) {
>
>         final SecurityContext currentSecurityContext =
> requestContext.getSecurityContext();
>         boolean secure = currentSecurityContext.isSecure();
>         requestContext.setSecurityContext(new
> InternalSecurityContext(subjectDetails, secure));
>
>     }
>
>     private boolean isTokenBasedAuthentication(String authorizationHeader)
> {
>
>         // Check if the Authorization header is valid
>         // It must not be null and must be prefixed with "Bearer" plus a
>         // whitespace
>         // The authentication scheme comparison must be case-insensitive
>         return StringUtils.startsWithIgnoreCase(authorizationHeader,
> AUTHENTICATION_SCHEME_PREFIX);
>     }
>
>     private void abortWithUnauthorized(ContainerRequestContext
> requestContext) {
>
>         // Abort the filter chain with a 401 status code response
>         // The WWW-Authenticate header is sent along with the response
>         requestContext.abortWith(
>                 Response.status(Response.Status.UNAUTHORIZED)
>                         .header(HttpHeaders.WWW_AUTHENTICATE,
>                                 AUTHENTICATION_SCHEME + " realm=\"" +
> Constants.APP_NAME + "\"")
>                         .build());
>     }
>
>     private void abortWithForbidden(ContainerRequestContext
> requestContext) {
>
>
> requestContext.abortWith(Response.status(Response.Status.FORBIDDEN).build());
>     }
>
>     static Permission getPermissionForResource(ResourceInfo resourceInfo) {
>
>         Permission permission =
> extractPermission(resourceInfo.getResourceMethod());
>         if (permission != null) {
>             return permission;
>         }
>         permission = extractPermission(resourceInfo.getResourceClass());
>         return permission;
>
>     }
>
>     // Extract Permission from the annotated element
>     static Permission extractPermission(AnnotatedElement annotatedElement)
> {
>
>         if (annotatedElement == null) {
>             return null;
>         }
>         Secured secured = annotatedElement.getAnnotation(Secured.class);
>         return secured == null ? null : secured.value();
>     }
>
>     private static class InternalSecurityContext implements
> SecurityContext {
>
>         private final boolean secure;
>
>         private final SubjectDetails subjectDetails;
>
>         InternalSecurityContext(SubjectDetails subjectDetails, boolean
> secure) {
>
>             this.subjectDetails = subjectDetails;
>             this.secure = secure;
>         }
>
>         @Override
>         public Principal getUserPrincipal() {
>
>             return subjectDetails;
>         }
>
>         @Override
>         public boolean isUserInRole(String role) {
>
>             // We are not using role base authorization
>             return true;
>         }
>
>         @Override
>         public boolean isSecure() {
>
>             return secure;
>         }
>
>         @Override
>         public String getAuthenticationScheme() {
>
>             return AUTHENTICATION_SCHEME;
>         }
>
>     }
>
>     /**
>      * For test purposes
>      *
>      * @param jwtService
>      * @return
>      */
>     public static TokenAuthenticationFilter createTestInstance(JwtService
> jwtService) {
>
>         TokenAuthenticationFilter filter = new TokenAuthenticationFilter();
>         filter.jwtService = jwtService;
>         return filter;
>     }
> }
>

The Secured annotation is used to mark the methods that need to be
protected and the required permission.

@NameBinding
> @Retention(RetentionPolicy.RUNTIME)
> @Target({ ElementType.TYPE, ElementType.METHOD })
> public @interface Secured {
>
>     Permission value() default Permission.AUTHENTICATED;
> }
>

João Assunção

Email: [email protected]
Mobile: +351 916968984
Phone: +351 211933149
Web: www.exploitsys.com




On Wed, Jun 22, 2022 at 8:54 PM Matthias Leinweber <
[email protected]> wrote:

> Hello Karaf user,
>
> i try to get aries-jax-rs-whiteboard in a version > 1.0.6 running without
> success. 2.0.1 with installed cxf is working fine. But in 1.0.7-1.0.10.
> http:list does not show a servlet and my jaxrs whiteboard resources are not
> working.
>
> Any hints which component needs to be installed? Reading BNDrun +
> Components DSL is pretty confusing.
>
> Btw, does anyone have a good example for authentication? Shiro seems to be
> a bit overkill.
>
> br,
> Matthias
>

Reply via email to