Thank you very much Joao...
lets see if i can somehow connect this with karaf jaas service

br,
Matthias

Am Mo., 27. Juni 2022 um 17:40 Uhr schrieb João Assunção <
[email protected]>:

> Hello Matthias.
>
> Sorry but I don't have a public repo with an example.
> I had some issues in the past when using more recent versions of Aries JAX
> RS due to conflicts with the CXF version I was using in another service, so
> I kept using version 1.0.4.
> In my latest projects, where I needed more customization, I ditched Aries
> JAX RS and used CXF directly. Needed more code and had to use
> JAXRSServerFactoryBean to create the server. Also lost the possibility to
> use service injection :-(
>
> The code for JWT is mostly taken from jose4j examples:
>
> @Component(service = JwtService.class, //
>>         immediate = true, //
>>         scope = ServiceScope.SINGLETON)
>> public class JwtService {
>>
>>     private static final Logger LOGGER =
>> LoggerFactory.getLogger(JwtService.class);
>>
>>     // time when the token will expire (minutes)
>>     private static final float TOKEN_TTL = 30;
>>
>>     public static final String ISSUER = "ACME";
>>
>>     public static final String AUDIENCE = "universe";
>>
>>     public static final String CLAIM_NAME = "name";
>>
>>     public static final String CLAIM_PERMISSIONS = "permissions";
>>
>>     private RsaJsonWebKey rsaJsonWebKey;
>>
>>     private JwtConsumer jwtConsumer;
>>
>>     @Activate
>>     public void activate() throws JoseException {
>>
>>         initWebKey();
>>         initJWTconsumer();
>>     }
>>
>>     private void initWebKey() throws JoseException {
>>
>>         rsaJsonWebKey = RsaJwkGenerator.generateJwk(2048);
>>         rsaJsonWebKey.setKeyId("keyId");
>>
>>     }
>>
>>     private void initJWTconsumer() {
>>
>>         jwtConsumer = new JwtConsumerBuilder()
>>                 .setRequireExpirationTime() // the JWT must have an
>> expiration
>>                                             // time
>>                 .setAllowedClockSkewInSeconds(30) // allow some leeway in
>>                                                   // validating time based
>>                                                   // claims to account
>> for clock
>>                                                   // skew
>>                 .setRequireSubject() // the JWT must have a subject claim
>>                 .setExpectedIssuer(ISSUER) // whom the JWT needs to have
>> been
>>                                            // issued by
>>                 .setExpectedAudience(AUDIENCE) // to whom the JWT is
>> intended
>>                                                // for
>>                 .setVerificationKey(rsaJsonWebKey.getKey()) // verify the
>>                                                             // signature
>> with
>>                                                             // the public
>> key
>>                 .setJwsAlgorithmConstraints( // only allow the expected
>>                                              // signature algorithm(s) in
>> the
>>                                              // given context
>>                         new
>> AlgorithmConstraints(ConstraintType.WHITELIST, // which
>>
>>  // is
>>
>>  // only
>>
>>  // RS256
>>
>>  // here
>>                                 AlgorithmIdentifiers.RSA_USING_SHA256))
>>                 .build(); // create the JwtConsumer instance
>>
>>     }
>>
>>     public String createToken(SubjectDetails subjectDetails) throws
>> AuthenticationException {
>>
>>         // Create the Claims, which will be the content of the JWT
>>         JwtClaims claims = new JwtClaims();
>>         claims.setIssuer(ISSUER); // who creates the token and signs it
>>         claims.setAudience(AUDIENCE); // to whom the token is intended to
>> be
>>                                       // sent
>>         claims.setExpirationTimeMinutesInTheFuture(TOKEN_TTL);
>>         claims.setGeneratedJwtId(); // a unique identifier for the token
>>         claims.setIssuedAtToNow(); // when the token was issued/created
>> (now)
>>         claims.setNotBeforeMinutesInThePast(2);
>>         claims.setSubject(subjectDetails.getId());
>>         claims.setStringClaim(CLAIM_NAME, subjectDetails.getName());
>>         claims.setStringListClaim(CLAIM_PERMISSIONS,
>> subjectDetails.getPermissionsList());
>>
>>         // A JWT is a JWS and/or a JWE with JSON claims as the payload.
>>         // In this example it is a JWS so we create a JsonWebSignature
>> object.
>>         JsonWebSignature jws = new JsonWebSignature();
>>
>>         // The payload of the JWS is JSON content of the JWT Claims
>>         jws.setPayload(claims.toJson());
>>
>>         // The JWT is signed using the private key
>>         jws.setKey(rsaJsonWebKey.getPrivateKey());
>>
>>         jws.setKeyIdHeaderValue(rsaJsonWebKey.getKeyId());
>>
>>         // Set the signature algorithm on the JWT/JWS that will integrity
>>         // protect the claims
>>
>> jws.setAlgorithmHeaderValue(AlgorithmIdentifiers.RSA_USING_SHA256);
>>
>>         try {
>>             return jws.getCompactSerialization();
>>         }
>>         catch (JoseException ex) {
>>             throw new AuthenticationException("Token creation failed",
>> ex);
>>         }
>>     }
>>
>>     public SubjectDetails validateToken(String token) throws
>> AuthenticationException {
>>
>>         try {
>>             JwtClaims jwtClaims = jwtConsumer.processToClaims(token);
>>             String subjectName =
>> jwtClaims.getStringClaimValue(CLAIM_NAME);
>>             List<String> permissions =
>> jwtClaims.getStringListClaimValue(CLAIM_PERMISSIONS);
>>             Set<Permission> permissionsSet =
>> Permission.fromList(permissions);
>>             permissionsSet.add(Permission.AUTHENTICATED); // Implicit
>> permission
>>             return new SubjectDetails(jwtClaims.getSubject(),
>> subjectName, permissionsSet);
>>         }
>>         catch (InvalidJwtException ex) {
>>             logException("InvalidJwtException", ex);
>>             throw new AuthenticationException(ex.getMessage());
>>
>>         }
>>         catch (MalformedClaimException ex) {
>>             logException("MalformedClaimException", ex);
>>             throw new AuthenticationException(ex.getMessage());
>>         }
>>
>>     }
>>
>>     protected static void logException(String msg, Exception ex) {
>>
>>         LOGGER.debug(msg, ex);
>>     }
>> }
>>
>
>
>
> João Assunção
>
> Email: [email protected]
> Mobile: +351 916968984
> Phone: +351 211933149
> Web: www.exploitsys.com
>
>
>
>
> On Mon, Jun 27, 2022 at 9:33 AM Matthias Leinweber <
> [email protected]> wrote:
>
>> Hello,
>>
>> I am using karaf 4.3.7 and yes I saw the examples in karaf. The version
>> used is 1.0.6 which is pretty old. I tried to update to 1.0.10 but i dont
>> see what is going wrong. There is the Application, Servlet, and Whiteboard.
>> But the servlet is not accessible.
>> With version 2.0.1 is cxf-core required. That would also be fine.
>> Unfortunately it does not work without a url prefix which would require a
>> change on the client side.
>>
>> @ João thank you very much for your help. Do you also have a repo link to
>> a working example; where does the JWTService come from?
>>
>> Thank
>> br,
>> Matthias
>>
>> Am Do., 23. Juni 2022 um 11:02 Uhr schrieb João Assunção <
>> [email protected]>:
>>
>>> 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