[
https://issues.apache.org/jira/browse/AMQ-9244?focusedWorklogId=866832&page=com.atlassian.jira.plugin.system.issuetabpanels:worklog-tabpanel#worklog-866832
]
ASF GitHub Bot logged work on AMQ-9244:
---------------------------------------
Author: ASF GitHub Bot
Created on: 21/Jun/23 19:29
Start Date: 21/Jun/23 19:29
Worklog Time Spent: 10m
Work Description: jbertram commented on code in PR #1035:
URL: https://github.com/apache/activemq/pull/1035#discussion_r1237586536
##########
activemq-broker/src/main/java/org/apache/activemq/security/jwt/JwtAuthenticationBroker.java:
##########
@@ -0,0 +1,179 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.activemq.security.jwt;
+
+import org.apache.activemq.broker.Broker;
+import org.apache.activemq.broker.ConnectionContext;
+import org.apache.activemq.command.ConnectionInfo;
+import org.apache.activemq.jaas.GroupPrincipal;
+import org.apache.activemq.security.AbstractAuthenticationBroker;
+import org.apache.activemq.security.SecurityContext;
+import org.jose4j.jwa.AlgorithmConstraints;
+import org.jose4j.jws.AlgorithmIdentifiers;
+import org.jose4j.jwt.JwtClaims;
+import org.jose4j.jwt.MalformedClaimException;
+import org.jose4j.jwt.consumer.InvalidJwtException;
+import org.jose4j.jwt.consumer.JwtConsumer;
+import org.jose4j.jwt.consumer.JwtConsumerBuilder;
+import org.jose4j.jwt.consumer.JwtContext;
+
+import java.security.Key;
+import java.security.KeyFactory;
+import java.security.NoSuchAlgorithmException;
+import java.security.Principal;
+import java.security.cert.X509Certificate;
+import java.security.spec.InvalidKeySpecException;
+import java.security.spec.X509EncodedKeySpec;
+import java.util.Base64;
+import java.util.Collections;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+/**
+ * Handle authentication an user based on a JWT token
+ */
+public class JwtAuthenticationBroker extends AbstractAuthenticationBroker {
+
+ private final String jwtIssuer;
+ private final Claims jwtGroupsClaim;
+ private final String jwtValidatingPublicKey;
+
+ public JwtAuthenticationBroker(
+ final Broker next,
+ final String jwtIssuer,
+ final Claims jwtGroupsClaim,
+ final String jwtValidatingPublicKey) {
+ super(next);
+ this.jwtIssuer = jwtIssuer;
+ this.jwtGroupsClaim = jwtGroupsClaim;
+ this.jwtValidatingPublicKey = jwtValidatingPublicKey;
+ }
+
+ @Override
+ public void addConnection(final ConnectionContext context, final
ConnectionInfo info) throws Exception {
+ SecurityContext securityContext = context.getSecurityContext();
+ if (securityContext == null) {
+ securityContext = authenticate(info.getUserName(),
info.getPassword(), null);
+ context.setSecurityContext(securityContext);
+ securityContexts.add(securityContext);
+ }
+
+ try {
+ super.addConnection(context, info);
+ } catch (Exception e) {
+ securityContexts.remove(securityContext);
+ context.setSecurityContext(null);
+ throw e;
+ }
+ }
+
+ @Override
+ public SecurityContext authenticate(final String username, final String
password, final X509Certificate[] certificates) throws SecurityException {
+ SecurityContext securityContext = null;
+ if (!username.isEmpty()) {
+
+ // parse the JWT token and check signature, validity, nbf
+ try {
+ final JwtConsumerBuilder builder = new JwtConsumerBuilder()
+ .setRelaxVerificationKeyValidation()
+ .setRequireSubject()
+ .setSkipDefaultAudienceValidation()
+ .setRequireExpirationTime()
+ .setExpectedIssuer(jwtIssuer)
+ .setAllowedClockSkewInSeconds(5)
+ .setVerificationKey(parsePCKS8(jwtValidatingPublicKey))
+ .setJwsAlgorithmConstraints(
+ new
AlgorithmConstraints(AlgorithmConstraints.ConstraintType.WHITELIST,
+ AlgorithmIdentifiers.RSA_USING_SHA256,
+ AlgorithmIdentifiers.RSA_USING_SHA384,
+ AlgorithmIdentifiers.RSA_USING_SHA512)
+ );
+
+ final JwtConsumer jwtConsumer = builder.build();
+ final JwtContext jwtContext = jwtConsumer.process(username);
Review Comment:
On [the
Jira](https://issues.apache.org/jira/browse/AMQ-9244?focusedCommentId=17723012&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-17723012)
it was indicated that the _password_ field should contain the token. If
`username` is used instead will this fit the reported use-case?
Issue Time Tracking
-------------------
Worklog Id: (was: 866832)
Time Spent: 1h 10m (was: 1h)
> Add JWT authentication plugin
> -----------------------------
>
> Key: AMQ-9244
> URL: https://issues.apache.org/jira/browse/AMQ-9244
> Project: ActiveMQ
> Issue Type: Task
> Components: Security/JAAS
> Reporter: Jean-Baptiste Onofré
> Assignee: Jean-Baptiste Onofré
> Priority: Major
> Fix For: 5.19.0, 5.18.2
>
> Time Spent: 1h 10m
> Remaining Estimate: 0h
>
--
This message was sent by Atlassian Jira
(v8.20.10#820010)