How Oauth can be used with Apache Qpid JMS 2.0 AMQP

prashantk2000
prashantk2000 Member Posts: 33 ✭✭

Hi All,

I am using Apache Qpid JMS 2.0 to connect standalone PS+ broker on 5671 port. I am able to achieve using username and password however I am not able to authenticate using Oauth.

Our other clients written in nodejs are able to authenticate and connect on 5671 with AMQP protocol and Oauth.

As per doc

I am providing the url and username and password as below

String solaceHost = "amqps://<host>:5671?amqp.saslMechanisms=XOAUTH2";

    String solaceUsername = Username

    String solacePassword = access_token

However, I do not have any luck here :(

Can someone please guide me here

Tagged:

Answers

  • marc
    marc Member, Administrator, Moderator, Employee Posts: 959 admin

    Hi @prashantk2000,

    Were you able to figure out the issue? What you're doing makes sense to me but I haven't tried it out myself.

  • prashantk2000
    prashantk2000 Member Posts: 33 ✭✭

    Hi Marc,

    We tried but we couldn't make it. :(

  • Aaron
    Aaron Member, Administrator, Moderator, Employee Posts: 644 admin

    Hi @prashantk2000. If this is still not resolved, can I ask a few questions? Your NodeJS apps: which API are they using? What exception does your JMS client see from the Solace broker? I'm assuming you've set the password to the actual access token? Not the string "access_token"..?? haha

    There may be additional details that you can see in the error response from the Solace broker if you can snoop the wireline traffic. Have you ever used WireShark? It can decode AMQP. It might be able to show some additional broker error message in the response/exception you get.

  • Markus
    Markus Member, Employee Posts: 7 Solace Employee

    Hello @prashantk2000 ,


    the following Code works for me and I just tested it again. It is with some debugging/experimental statements, but it should make clear how it works:

    package com.solace.oauth.demos;
    
    
    import org.apache.qpid.jms.JmsContext;
    import org.apache.qpid.jms.JmsTopic;
    
    import com.solace.oauth.azuread.AccessData;
    import com.solace.oauth.azuread.TokenClientDemonet;
    import org.apache.qpid.jms.JmsConnectionFactory;
    import org.json.JSONObject;
    
    import java.time.LocalDateTime;
    import java.util.Base64;
    
    /**
     * Subscribes to messages published to a topic using Apache Qpid JMS 2.0 API over AMQP 1.0 Solace Message Router is used as the
     * message broker.
     * This is the Subscriber in the Publish/Subscribe messaging pattern.
     */
    public class AMQPTopicSubscriberOAUTH {
    
        //Use a Topic where you have access to (check the ACL of the Authorization Group)
        final String TOPIC_NAME = "app1/oauth";
    
        private void run() throws Exception {
    
            //completely independent logic to retrieve the Access Token
            //here we get the complete response from the ID Provider and need to process it
            String idpResponse = TokenClientDemonet.retrieveAzureToken();
    
            //Get the AccessToken from the IDP Response, this is depending on what your Token Client does
            JSONObject obj = new JSONObject(idpResponse);
            String AccessToken = obj.getString("access_token");
            System.out.println("The Access Token is: "+AccessToken);
    
            //just to print the Token as JSON
            String[] allTokens = AccessToken.split("\\.");
            byte[] decodedBytes = Base64.getDecoder().decode(allTokens[1]);
            String decodedToken = new String(decodedBytes);
            System.out.println("Decoded Token is: "+decodedToken);
    
            // AMQP_HOST_URL is something like amqps://mr-connection-xyzabc4711g.messaging.solace.cloud:5671
            String solaceHost = AccessData.AMQP_HOST_URL +"?amqp.saslMechanisms=XOAUTH2";
            String username = AccessData.VPN_USER_NAME;
    
            System.out.println("Timestamp: "+ LocalDateTime.now());
    
            String solacePassword = AccessToken;
    
            System.out.printf("AMQPTopicSubscriber is connecting to Solace router %s...%n", solaceHost);
    
            // Programmatically create the connection factory using default settings
            JmsConnectionFactory connectionFactory = new JmsConnectionFactory(username, solacePassword, solaceHost);
    
            // Establish connection that uses the Solace Message Router as a message broker
            try (JmsContext context = (JmsContext) connectionFactory.createContext()) {
    
                System.out.printf("Connected to the Solace router with client username '%s'.%n", username);
    
                // Create the publishing topic programmatically
                JmsTopic topic = (JmsTopic) context.createTopic(TOPIC_NAME);
    
                System.out.println("Awaiting message for Topic "+TOPIC_NAME);
                // create consumer and wait for a message to arrive.
                // the current thread blocks at the next statement until a message arrives
                String message = context.createConsumer(topic).receiveBody(String.class);
    
                System.out.printf("Message received: '%s'%n", message);
            }
        }
    
        public static void main(String[] args) throws Exception {
    
            new AMQPTopicSubscriberOAUTH().run();
        }
    }
    


  • prashantk2000
    prashantk2000 Member Posts: 33 ✭✭

    Thank you @Markus. We are using Keycloak IDP and JWT token for authorization, I hope we can check with this reference snippet. We will try this at our end.

    @Aaron We are using rhea lib for nodejs.

  • cpjani
    cpjani Member Posts: 5

    Hi @Markus, we are trying to check it but unable to find dependency for import com.solace.oauth.azuread.AccessData & import com.solace.oauth.azuread.TokenClientDemonet so can u pls help us ? from where we can get dependency ?

  • Markus
    Markus Member, Employee Posts: 7 Solace Employee

    Hi @cpjani ,

    this 2 java classes are just my implementation of getting the token from Azure and storing the necessary usernames, hostnames, and so on (which is not a recommended way in production code).

    You will have different ways and values anyway. BTW, I generated the TokenClient Java code from Postman, after it was successful to get a token with the Postman calls. See this screenshot:

    If you are using KeyCloak, it might be even easier to get a token, did you read Pauls and Victors Blog on that topic?


    If you like, I can clean up package my code examples, but it is not very elegant, just demo code...