Creating Utilities to Manipulate Users in #Weblogic Using #JMX and #MBeans

INTRO

First I’d like to apologies for the big absent on my side as I was very busy traveling to KSA for a new freelancing Client, but anyway I hope this article make you forgive me :)

Weblogic is a great Application Server, and the one you can count on for your heavy industrial deployment, load balancing, high availability and clustering.

Not only that but it comes with a great scripting tool WLST and the standardization of accessing its MBeans through JMX

There were an old school approach which would allow you to access MBeans through Weblogic APIs itself like so

import weblogic.management.Helper;
import weblogic.management.MBeanHome;
public class UseHelper {
    public static void main(String[] args) {
        String url = "t3://localhost:7001";
        String username = "weblogic";
        String password = "weblogic";
        String msName = "MS1";
        MBeanHome localHome = null;
        try {
            localHome = (MBeanHome)Helper.getMBeanHome(username, password, url,
                       msName);
            System.out.println("Local MBeanHome for" + localHome +
                       " found using the Helper class");
        } catch (IllegalArgumentException iae) {
            System.out.println("Illegal Argument Exception: " + iae);
        }
    }
}

But as you write this in your JDeveloper or favorite Editor, you will realize that this has been deprecated!

So the better alternative, and the hard way around it is to use JMX

THE DEFINITION

JMX(Java Management Extension) is a technology that represents a universal, open technology for management, and monitoring applications, system objects, devices (e. g. printers) and service oriented networks. Those resources are represented by objects called MBeans (for Managed Beans)

So Enough with the definitions, lets get to work.

THE UTILITY CLASS

What we want here is accessing Weblogic MBeans to get Users for DefaultAuthenticator -Default authenticator on Weblogic and Get Users, Groups and doing some manipulation like adding, editing, deleting and reset password for users in Weblogic Default Authenticator -You can edit it to suit your need but remember if the authenticator is read only you will get exceptions trying to alter users.

So lets get Started, first by checking MBeans Reference We will realize that in Order to access the Users we have to go this path:

  • Configuration MBeans
    • Domain Configuration MBeans
      • Security Configuration MBean
        • Default Realm (Attribute of Security Configuration MBean and an instance of RealmMBean)
          • AuthenticationProviders (Attribute of Default Realm and an instance of AuthenticationProviderMBean[])

So How do we do that, let’s start write some code

THE INITIALIZATION CODE

We will start my making a connection to Weblogic Server instance, and then drill down to AuthenticationProviderMBean(s)
Remember this is a utilities Class, that’s why all of my methods will be static

/****** DEFINING SOME STATIC VARIABLES ********/
public static final String JNDI_FACTORY = "weblogic.jndi.WLInitialContextFactory";
public static final String MBEAN_SERVER = "weblogic.management.mbeanservers.domainruntime";
public static final String JNDI_ROOT = "/jndi/";
public static final String DEFAULT_PROTOCOL = "t3";
public static final String PROTOCOL_PROVIDER_PACKAGES = "weblogic.management.remote";
//This how we get our DomainRuntimeService, this is where DomainConfigurationMBeans exists
public static final String DOMAIN_MBEAN_NAME = "com.bea:Name=DomainRuntimeService,Type=weblogic.management.mbeanservers.domainruntime.DomainRuntimeServiceMBean";
private static MBeanServerConnection connection;
private static ObjectName defaultAuthenticator;
private static ObjectName[] authenticationProviders;
private static String authenticatorName="DefaultAuthenticator";

Okay, now we defined it, let’s drill down to our AuthenticationProviders

static {
        try {
            String host = "127.0.0.1";
            String port = "7101";
            String username = "weblogic";
            String password = "weblogic1";
            Hashtable h = new Hashtable();
            JMXServiceURL serviceURL;

            serviceURL =
                    new JMXServiceURL(DEFAULT_PROTOCOL, host, Integer.valueOf(port).intValue(),
                                      "/jndi/weblogic.management.mbeanservers.domainruntime");

            h.put("java.naming.security.principal", username);
            h.put("java.naming.security.credentials", password);
            h.put("jmx.remote.protocol.provider.pkgs",
                  "weblogic.management.remote");

            //Creating a JMXConnector to connect to JMX
            JMXConnector connector =
                JMXConnectorFactory.connect(serviceURL, h);

            connection = connector.getMBeanServerConnection();

            /****
              We Get Objects by creating ObjectName with it's Qualified name.
              The constructor take a String of the full Qualified name of the MBean
              We then use connection to get Attribute out of this ObjectName but specifying a String of
              this Attribute
              *****/

            ObjectName configurationMBeans=
                new ObjectName(DOMAIN_MBEAN_NAME);
            ObjectName domain =
                (ObjectName)connection.getAttribute(configurationMBeans, "DomainConfiguration");

            ObjectName security =
                (ObjectName)connection.getAttribute(domain, "SecurityConfiguration");

            ObjectName realm =
                (ObjectName)connection.getAttribute(security, "DefaultRealm");

            authenticationProviders =
                    (ObjectName[])connection.getAttribute(realm,
                                                          "AuthenticationProviders");

            for (int i = 0; i < authenticationProviders.length; i++) {
                String name =
                    (String)connection.getAttribute(authenticationProviders[i],
                                                    "Name");

                if (name.equals(authenticatorName))
                    defaultAuthenticator = authenticationProviders[i];
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

WOHOO you’ve done a great step, you now have a reference to the defaultAuthenticator MBean, now you can make operations on users and Groups

DEEP INSIDE DEFAULTAUTHENTICATORMBEAN

If you looked at the reference of DefaultAuthenticatorMBean which is a subclass of AuthenticationProviderMBean you will realize the following:

Attributes

Operations

Now I guess you know what do we need to do right, Excellent so lets get it done

THE USER/GROUP MANIPULATION

public static boolean addUser(String username, String psw, String desc) {
        try {
            /** As of connection.getAttribute you can use connection.invoke to invoke an action
                It Takes ObjectName, String OperationName, Object[] Parameters, and String[] Parameters
                Definition
            **/
            connection.invoke(defaultAuthenticator, "createUser",
                              new Object[] { username, psw, desc },
                              new String[] { "java.lang.String",
                                             "java.lang.String",
                                             "java.lang.String" });

            return true;
        } catch (Exception e) {
            return false;
            //throw new RuntimeException(e);
        }
    }

    public static boolean removeUser(String username) {
        try {
            if (!username.equalsIgnoreCase("weblogic")) {
                connection.invoke(defaultAuthenticator, "removeUser",
                                  new Object[] { username },
                                  new String[] { "java.lang.String" });
            }

            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

    public static boolean resetUserPassword(String username,
                                            String newPassword) {
        try {
            if (!username.equalsIgnoreCase("weblogic")) {
                connection.invoke(defaultAuthenticator, "resetUserPassword",
                                  new Object[] { username, newPassword },
                                  new String[] { "java.lang.String",
                                                 "java.lang.String" });
            }

            return true;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return false;
    }

           /** As of connection.getAttribute you can use connection.invoke to invoke an action
                It Takes ObjectName, String OperationName, Object[] Parameters, and String[] Parameters
                Definition, It returns an Object we cast it to Boolean, you can know all about function from
                MBeans Reference
            **/
    public static boolean isUserExists(String currentUser) throws RuntimeException {
        try {
            boolean userExists =
                ((Boolean)connection.invoke(defaultAuthenticator, "userExists",
                                            new Object[] { currentUser },
                                            new String[] { "java.lang.String" })).booleanValue();

            return userExists;
        } catch (Exception ex) {
throw new RuntimeException(ex);
        }
    }

    public static boolean isGroupExists(String currentGroup) throws RuntimeException {
        try {
            boolean gourpExists =
                ((Boolean)connection.invoke(defaultAuthenticator,
                                            "groupExists",
                                            new Object[] { currentGroup },
                                            new String[] { "java.lang.String" })).booleanValue();

            return gourpExists;
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    /** This one is tricky, You first obtain a String cursor of the Iterator of Users, then you check if
        It have current, while true we invoke another function called "getCurrentName" which returns the name
        of the user, then I call advance function for the cursor to move forward, and invoke haveCurrent again
        and assign it to the same boolean I entered the while with (In order to get out of it!)
    **/
    public static List getListOfUsers() throws RuntimeException {
        try {
            List allUsers = new ArrayList();

            String cursor =
                (String)connection.invoke(defaultAuthenticator, "listUsers",
                                          new Object[] { "*",
                                                         Integer.valueOf(9999) },
                                          new String[] { "java.lang.String",
                                                         "java.lang.Integer" });

            boolean haveCurrent =
                ((Boolean)connection.invoke(defaultAuthenticator,
                                            "haveCurrent",
                                            new Object[] { cursor },
                                            new String[] { "java.lang.String" })).booleanValue();

            while (haveCurrent) {
                String currentName =
                    (String)connection.invoke(defaultAuthenticator,
                                              "getCurrentName",
                                              new Object[] { cursor },
                                              new String[] { "java.lang.String" });

                allUsers.add(currentName);
                connection.invoke(defaultAuthenticator, "advance",
                                  new Object[] { cursor },
                                  new String[] { "java.lang.String" });

                haveCurrent =
                        ((Boolean)connection.invoke(defaultAuthenticator, "haveCurrent",
                                                    new Object[] { cursor },
                                                    new String[] { "java.lang.String" })).booleanValue();
            }

            return allUsers;
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    public static List getUserGroups(String username) throws RuntimeException {
        try {
            List allUserGroups = new ArrayList();

            String cursor =
                (String)connection.invoke(defaultAuthenticator, "listMemberGroups",
                                          new Object[] { username },
                                          new String[] { "java.lang.String"});

            boolean haveCurrent =
                ((Boolean)connection.invoke(defaultAuthenticator,
                                            "haveCurrent",
                                            new Object[] { cursor },
                                            new String[] { "java.lang.String" })).booleanValue();

            while (haveCurrent) {
                String currentName =
                    (String)connection.invoke(defaultAuthenticator,
                                              "getCurrentName",
                                              new Object[] { cursor },
                                              new String[] { "java.lang.String" });

                allUserGroups.add(currentName);

                connection.invoke(defaultAuthenticator, "advance",
                                  new Object[] { cursor },
                                  new String[] { "java.lang.String" });

                haveCurrent =
                        ((Boolean)connection.invoke(defaultAuthenticator, "haveCurrent",
                                                    new Object[] { cursor },
                                                    new String[] { "java.lang.String" })).booleanValue();
            }

            return allUserGroups;
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    public static List getGroupMembers(String groupName) throws RuntimeException {
        try {
            List allGroupMembers = new ArrayList();

            String cursor =
                (String)connection.invoke(defaultAuthenticator, "listGroupMembers",
                                          new Object[] { groupName, "*", new java.lang.Integer(0) },
                                          new String [] { "java.lang.String", "java.lang.String", "java.lang.Integer" });

            boolean haveCurrent =
                ((Boolean)connection.invoke(defaultAuthenticator,
                                            "haveCurrent",
                                            new Object[] { cursor },
                                            new String[] { "java.lang.String" })).booleanValue();

            while (haveCurrent) {
                String currentName =
                    (String)connection.invoke(defaultAuthenticator,
                                              "getCurrentName",
                                              new Object[] { cursor },
                                              new String[] { "java.lang.String" });

                allGroupMembers.add(currentName);

                connection.invoke(defaultAuthenticator, "advance",
                                  new Object[] { cursor },
                                  new String[] { "java.lang.String" });

                haveCurrent =
                        ((Boolean)connection.invoke(defaultAuthenticator, "haveCurrent",
                                                    new Object[] { cursor },
                                                    new String[] { "java.lang.String" })).booleanValue();
            }

            return allGroupMembers;
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }

    public static List getListOfGroups() throws RuntimeException {
        try {
            List allUsers = new ArrayList();

            String cursor =
                (String)connection.invoke(defaultAuthenticator, "listGroups",
                                          new Object[] { "*",
                                                         Integer.valueOf(9999) },
                                          new String[] { "java.lang.String",
                                                         "java.lang.Integer" });

            boolean haveCurrent =
                ((Boolean)connection.invoke(defaultAuthenticator,
                                            "haveCurrent",
                                            new Object[] { cursor },
                                            new String[] { "java.lang.String" })).booleanValue();

            while (haveCurrent) {
                String currentName =
                    (String)connection.invoke(defaultAuthenticator,
                                              "getCurrentName",
                                              new Object[] { cursor },
                                              new String[] { "java.lang.String" });

                allUsers.add(currentName);

                connection.invoke(defaultAuthenticator, "advance",
                                  new Object[] { cursor },
                                  new String[] { "java.lang.String" });

                haveCurrent =
                        ((Boolean)connection.invoke(defaultAuthenticator, "haveCurrent",
                                                    new Object[] { cursor },
                                                    new String[] { "java.lang.String" })).booleanValue();
            }

            return allUsers;
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
    }
And that’s it, Enjoy your Weblogic Utility Class :)

Comments