Every Authentication Provider must implement the weblogic.security.spi.AuthenticationProviderV2
interface, which is the real contract between WebLogic's Security Services and our implementation, as shown in the following code snippet:
public class PacktAuthProviderImpl implements AuthenticationProviderV2 { private static final Logger LOGGER = Logger.getLogger(PacktAuthProviderImpl.class.getSimpleName()); @Override public void initialize(ProviderMBean mbean, SecurityServices services) { LOGGER.info("PacktAuthProviderImpl.initialize"); } @Override public String getDescription() { return null; } @Override public void shutdown() { LOGGER.info("PacktAuthProviderImpl.shutdown"); } @Override public AppConfigurationEntry getLoginModuleConfiguration() { return null; } @Override public AppConfigurationEntry getAssertionModuleConfiguration() { return null; } @Override public PrincipalValidator getPrincipalValidator() { return null; } @Override public IdentityAsserterV2 getIdentityAsserter() { return null; } }
And yes, now you can install and configure the provider in your domain; you will see the following single line of log:
net.lucamasini.security.PacktAuthProviderImpl initialize INFO: PacktAuthProviderImpl.initialize
It's not much, but it means that our configuration and infrastructure is working fine. From now on, finally, we will really code there, giving behavior to the PacktAuthProviderImpl
class that WebLogic now knows is a custom provider.
Every framework
has its own lifecycle, and every lifecycle has a start and an end. For AuthenticationProviderV2
these are the callback methods initialize
and shutdown
, where we can not only eventually instantiate our custom objects but also grab configuration from the MBean that wraps our class and communicates with the console. In this simple implementation, we don't need to do anything inside shutdown
, so we'll leave the current one that logs a line when it is called.
Instead, a lot must be done inside the initialize
method, where we receive the MBean instance and the Security Service, which is our actual container. The first thing we need to do is cast the generic ProviderMBean
to our custom MBean so that we can use our specific attributes, as follows:
PacktSiteUsersAuthenticationMBean myMBean = (PacktSiteUsersAuthenticationMBean) mbean;
Now that we have our specific instance, we can save the configuration for later use using the following code snippet:
description = myMBean.getDescription() + " " + myMBean.getVersion(); url = myMBean.getURL();
Here description
and url
are two instance string fields. We also need to save an instance of AppConfigurationEntry.LoginModuleControlFlag
, which is a JAAS version of an enum type (old style Java) that tells us if our Security Provider is mandatory or not. This can be done as follows:
String flag = myMBean.getControlFlag(); try { controlFlag =(AppConfigurationEntry.LoginModuleControlFlag) AppConfigurationEntry.LoginModuleControlFlag.class.getField(flag).get(null); } catch (Exception e) { throw new IllegalArgumentException("invalid flag value" + flag,e); }
In this first stage, we can print the configuration output on WebLogic's Server log so that we can be sure that we call the correct parameter and our simple parsing code is working fine. Use the following code:
LOGGER.info("ControlFlag: "+controlFlag); LOGGER.info("Description: "+description); LOGGER.info("URL: "+url);
We should see something like the following:
INFO: ControlFlag: LoginModuleControlFlag: optional INFO: Description: WebLogic Packt Authentication Provider 1.0 INFO: URL: http://external-user.intra.net/checkUserLogin
Our
implementation is almost finished; we now need to implement the remaining method, getDescription
. This is quite straightforward, as shown in the following code:
@Override public String getDescription() { return description; }
While getIdentityAsserter
will continue to return null (as we are coding an Authentication Provider), we still need to implement the Principal Validator, and for that we can use a built-in validator that comes with WebLogic, as shown in the following code snippet:
@Override public PrincipalValidator getPrincipalValidator() { return new weblogic.security.provider.PrincipalValidatorImpl(); }
Finally, the
configuration of JAAS LoginModule
, which will actually do the authentication. We will not use any standard LoginModule
, rather we will use our own:
@Override public AppConfigurationEntry getLoginModuleConfiguration() { return new AppConfigurationEntry( "net.lucamasini.security.PacktLoginModuleImpl", controlFlag, new HashMap<String, Object>() {{ put("url", url); }} ); } @Override public AppConfigurationEntry getAssertionModuleConfiguration() { return getLoginModuleConfiguration(); }
We can now install and start WebLogic. Strangely, it will not complain about the fact that the PacktLoginModuleImpl
class is missing; it will merely ignore this Authentication Provider during the login process. This can be seen as an error, but it is a good and conservative practice and in case we want/need to check if our configuration has been read correctly, we can always enable the atn debug flag by going to weblogic.security.atn in the console or start up script and look for PacktLoginModuleImpl
.