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
>