Subscribing to Posture Topic

The pxGrid client subscribes to the Posture topic so they can obtain the Posture information in real-time. For more information on the Posture Configuration topic, please see: Posture Configuration

Code Step-Through

The //Subscribe handler class this will print the contents of the session that is opened by STOMP.

Main parses the SampleConfiguration config file. The sample config object contains the pxGrid client connection parameters such as the pxGrid hostname, identity filename (.jks file) and trusted keystore filesname (.jks file) or pre-share keys if implemented.

For //Account Activate, we wait 60 seconds for the account to be enabled. The ISE admin need to approve the pxGrid client account. We retrieve the pxGrid controller version.

For // pxGrid ServiceLookup for posture data service, we lookup the posture data service, com.cisco.ise.posture, since we are interested in obtaining the posture data information. The posture data service can be found:Github. This returns a list of the ISE nodes that are publishing the restBaseURL that will be used for WebSockets REST API calls.

For // Use first service. Note that ServiceLookup randomize ordering of services. The pubsub service provides a list of ISE pxGrid nodes, if you have Active/Active.
For example if you have (3) ISE pxGrid nodes, the value is randomized so you will only connect to one pxGrid node. However the service will be shared across all three ISE pxGrid nodes, this distributes the load. We get the properties for “wsPubService” and “postureVisibilityTopic” service names. All the services use WebSockets Pubsub service name, “com.cisco.ise.pubsub” and here we interested in the postureVisibilityTopic, com.cisco.ise.posture".

For //pxGrid service Lookup for pubsub service, this provides us with the ISE pxgrid node the publishes the posture data service

For //Use first service, we get pubsub service which resturns the “wsUrl” or WebSockets URL value

For //pxGrid get AccessSecret, we get the accessecret from the ISE pxGrid node containing the pubsub service.

For //WebSocket config, we get the credentials

For //WebSocket connect, we first make a WebSockets connection and then create a STOMP over WebSockets connection

For //Stompconnect, the pxGrid client connects

For //Subscribe, the pxGrid client subscribes to the poature topic over STOMP

For //Give time for connection to establish before prompt disconnect. Once the endpoint disconnects, the ID “ID-123”, which can be any value, provides a receipt. The ISE pxGrid node will send back an acknowledgement to say that the pxGrid client has disconnected

JAVA Sample Code

package com.cisco.pxgrid.samples.ise;

import com.cisco.pxgrid.samples.ise.model.AccountState;
import com.cisco.pxgrid.samples.ise.model.Service;
import org.apache.commons.cli.ParseException;
import org.glassfish.tyrus.client.ClientManager;
import org.glassfish.tyrus.client.ClientProperties;
import org.glassfish.tyrus.client.SslEngineConfigurator;
import org.glassfish.tyrus.client.auth.Credentials;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.net.URI;

/**
 * Demonstrates how to subscribe to RADIUS Failure Topic
 */
public class PostureDataSubscribe {
    public static final String SERVICE_NAME = "com.cisco.ise.posture";

    private static Logger logger = LoggerFactory.getLogger(PostureDataSubscribe.class);

    // Subscribe handler class
    private static class DataHandler implements StompSubscription.Handler {
        @Override
        public void handle(StompFrame message) {
            logger.info("Content={}", new String(message.getContent()));
        }
    }

    public static void main(String[] args) throws Exception {
        // Parse arguments
        SampleConfiguration config = new SampleConfiguration();
        try {
            config.parse(args);
        } catch (ParseException e) {
            config.printHelp("Subscribe");
            System.exit(1);
        }

        // AccountActivate
        PxgridControl control = new PxgridControl(config);
        while (control.accountActivate() != AccountState.ENABLED) {
            Thread.sleep(60000);
        }
        logger.info("pxGrid controller version={}", control.getControllerVersion());

        // pxGrid ServiceLookup for posture data service
        Service[] services = control.serviceLookup(SERVICE_NAME);
        if (services.length == 0) {
            logger.info("Posture service unavailabe");
            return;
        }

        // Use first service. Note that ServiceLookup randomize ordering of services
        Service postureService = services[0];
        String wsPubsubServiceName = postureService.getProperties().get("wsPubsubService");
        String postureVisibilityTopic = postureService.getProperties().get("postureVisibilityTopic");
        logger.info("wsPubsubServiceName={} postureVisibilityTopic={}", wsPubsubServiceName, postureVisibilityTopic);

        // pxGrid ServiceLookup for pubsub service
        services = control.serviceLookup(wsPubsubServiceName);
        if (services.length == 0) {
            logger.info("Pubsub service unavailabe");
            return;
        }

        // Use first service
        Service wsPubsubService = services[0];
        String wsURL = wsPubsubService.getProperties().get("wsUrl");
        logger.info("wsUrl={}", wsURL);

        // pxGrid get AccessSecret
        String secret = control.getAccessSecret(wsPubsubService.getNodeName());


        // WebSocket config
        ClientManager client = ClientManager.createClient();
        SslEngineConfigurator sslEngineConfigurator = new SslEngineConfigurator(config.getSSLContext());
        client.getProperties().put(ClientProperties.SSL_ENGINE_CONFIGURATOR, sslEngineConfigurator);
        client.getProperties().put(ClientProperties.CREDENTIALS,
                new Credentials(config.getNodeName(), secret.getBytes()));

        // WebSocket connect
        StompPubsubClientEndpoint endpoint = new StompPubsubClientEndpoint();
        URI uri = new URI(wsURL);
        javax.websocket.Session session = client.connectToServer(endpoint, uri);

        // STOMP connect
        endpoint.connect(uri.getHost());

        // Subscribe
        StompSubscription subscription = new StompSubscription(postureVisibilityTopic, new DataHandler());
        endpoint.subscribe(subscription);

        // Give time for connection to establish before prompt
        Thread.sleep(1000);
        SampleHelper.prompt("press <enter> to disconnect...");

        // STOMP disconnect
        endpoint.disconnect("ID-123");
        // Wait for disconnect receipt
        Thread.sleep(3000);

        // Websocket close
        session.close();
    }
}

Output

/Library/Java/JavaVirtualMachines/jdk-11.0.14.jdk/Contents/Home/bin/java -javaagent:/Applications/IntelliJ IDEA CE.app/Contents/lib/idea_rt.jar=51023:/Applications/IntelliJ IDEA CE.app/Contents/bin -Dfile.encoding=UTF-8 -classpath /Users/userhome/IdeaProjects/Sep2022/pxgrid-rest-ws/java/target/classes:/Users/userhome/.m2/repository/javax/xml/bind/jaxb-api/2.2.11/jaxb-api-2.2.11.jar:/Users/userhome/.m2/repository/javax/websocket/javax.websocket-api/1.1/javax.websocket-api-1.1.jar:/Users/userhome/.m2/repository/org/glassfish/tyrus/tyrus-client/1.17/tyrus-client-1.17.jar:/Users/userhome/.m2/repository/org/glassfish/tyrus/tyrus-core/1.17/tyrus-core-1.17.jar:/Users/userhome/.m2/repository/org/glassfish/tyrus/tyrus-spi/1.17/tyrus-spi-1.17.jar:/Users/userhome/.m2/repository/jakarta/xml/bind/jakarta.xml.bind-api/2.3.2/jakarta.xml.bind-api-2.3.2.jar:/Users/userhome/.m2/repository/jakarta/activation/jakarta.activation-api/1.2.1/jakarta.activation-api-1.2.1.jar:/Users/userhome/.m2/repository/org/glassfish/tyrus/tyrus-container-grizzly-client/1.17/tyrus-container-grizzly-client-1.17.jar:/Users/userhome/.m2/repository/org/glassfish/grizzly/grizzly-framework/2.3.22/grizzly-framework-2.3.22.jar:/Users/userhome/.m2/repository/org/glassfish/grizzly/grizzly-http-server/2.3.22/grizzly-http-server-2.3.22.jar:/Users/userhome/.m2/repository/org/glassfish/grizzly/grizzly-http/2.3.22/grizzly-http-2.3.22.jar:/Users/userhome/.m2/repository/com/google/code/gson/gson/2.1/gson-2.1.jar:/Users/userhome/.m2/repository/commons-io/commons-io/2.7/commons-io-2.7.jar:/Users/userhome/.m2/repository/commons-cli/commons-cli/1.4/commons-cli-1.4.jar:/Users/userhome/.m2/repository/org/slf4j/slf4j-api/1.7.25/slf4j-api-1.7.25.jar:/Users/userhome/.m2/repository/ch/qos/logback/logback-core/1.2.0/logback-core-1.2.0.jar:/Users/userhome/.m2/repository/ch/qos/logback/logback-classic/1.2.0/logback-classic-1.2.0.jar:/Users/userhome/.m2/repository/org/apache/commons/commons-lang3/3.8.1/commons-lang3-3.8.1.jar com.cisco.pxgrid.samples.ise.PostureDataSubscribe -a 10.76.231.99 -u pxtest002 -k /Users/userhome/ise99/self1.jks -p cisco123 -t /Users/userhome/ise99/root1.jks -q cisco123
------ config ------
  hostname = 10.76.231.99
  nodename = pxtest002
  password = (not specified)
  description = (not specified)
  keystorefilename = /Users/userhome/ise99/self1.jks
  keystorepassword = cisco123
  truststorefilename = /Users/userhome/ise99/root1.jks
  truststorepassword = cisco123
--------------------
11:22:04.896 [main] INFO com.cisco.pxgrid.samples.ise.PxgridControl - AccountActivate request={}
11:22:05.253 [main] INFO com.cisco.pxgrid.samples.ise.PxgridControl - AccountActivate response={"accountState":"ENABLED","version":"2.0"}
11:22:05.254 [main] INFO com.cisco.pxgrid.samples.ise.PostureDataSubscribe - pxGrid controller version=2.0
11:22:05.259 [main] INFO com.cisco.pxgrid.samples.ise.PxgridControl - ServiceLookup request={"name":"com.cisco.ise.posture"}
11:22:05.314 [main] INFO com.cisco.pxgrid.samples.ise.PxgridControl - ServiceLookup response={"services":[{"name":"com.cisco.ise.posture","nodeName":"~ise-admin-iselab99","properties":{"postureVisibilityTopic":"/topic/com.cisco.ise.posture.visibility","wsPubsubService":"com.cisco.ise.pubsub","restBaseUrl":"https://iselab99.cisco.com:8910/pxgrid/ise/posture"}}]}
11:22:05.314 [main] INFO com.cisco.pxgrid.samples.ise.PostureDataSubscribe - wsPubsubServiceName=com.cisco.ise.pubsub postureVisibilityTopic=/topic/com.cisco.ise.posture.visibility
11:22:05.316 [main] INFO com.cisco.pxgrid.samples.ise.PxgridControl - ServiceLookup request={"name":"com.cisco.ise.pubsub"}
11:22:05.369 [main] INFO com.cisco.pxgrid.samples.ise.PxgridControl - ServiceLookup response={"services":[{"name":"com.cisco.ise.pubsub","nodeName":"~ise-pubsub-iselab99","properties":{"wsUrl":"wss://iselab99.cisco.com:8910/pxgrid/ise/pubsub"}}]}
11:22:05.369 [main] INFO com.cisco.pxgrid.samples.ise.PostureDataSubscribe - wsUrl=wss://iselab99.cisco.com:8910/pxgrid/ise/pubsub
11:22:05.370 [main] INFO com.cisco.pxgrid.samples.ise.PxgridControl - AccessSecret request={"peerNodeName":"~ise-pubsub-iselab99"}
11:22:05.430 [main] INFO com.cisco.pxgrid.samples.ise.PxgridControl - AccessSecret response={"secret":"zD8QCRoasA6XEVN1"}
11:22:06.477 [Grizzly(2)] INFO com.cisco.pxgrid.samples.ise.StompPubsubClientEndpoint - WS onOpen
11:22:06.481 [main] INFO com.cisco.pxgrid.samples.ise.StompPubsubClientEndpoint - STOMP CONNECT host=iselab99.cisco.com
11:22:06.487 [main] INFO com.cisco.pxgrid.samples.ise.StompPubsubClientEndpoint - STOMP SUBSCRIBE topic=/topic/com.cisco.ise.posture.visibility
11:22:06.492 [Grizzly(1)] INFO com.cisco.pxgrid.samples.ise.StompPubsubClientEndpoint - STOMP CONNECTED version=1.2
press <enter> to disconnect...

What you see in ISE

Select Administration->pxGrid Services->Diagnostics->WebSocket