我想在Karaf Jaas框架中添加一个自定义的LoginModule,并创建一个将使用它的新领域。
我该怎么做?
答案 0 :(得分:3)
我有自己的解决方案如下,使用Declarative Services实现。
首先,创建一个新的LoginModule
实施,扩展org.apache.karaf.jaas.modules.AbstractKarafLoginModule
。
public class CustomLoginModule extends AbstractKarafLoginModule
{
public void initialize(Subject subject, CallbackHandler callbackHandler,
Map<String, ?> sharedState, Map<String, ?> options)
{
super.initialize(subject, callbackHandler, options);
// Use the `options` parameter for extra information that will be used
// inside the module; this is passed from the JaasRealm service
}
public boolean login() throws LoginException
{
// prepare callback objects and get the authentication information
Callback[] callbacks = new Callback[2];
callbacks[0] = new NameCallback("Username: ");
callbacks[1] = new PasswordCallback("Password: ", false);
try {
callbackHandler.handle(callbacks);
}
catch (Exception e) {
throw new LoginException(e.getMessage());
}
user = ((NameCallback) callbacks[0]).getName();
char[] tmpPassword = ((PasswordCallback) callbacks[1]).getPassword();
if (tmpPassword == null)
tmpPassword = new char[0];
String password = new String(tmpPassword);
// Do the custom authentication and throw `LoginException` if the user
// is not valid. Get the roles and groups that the user is assigned to.
// .......
// Add roles and groups along with the user information to the `principals`
principals = new HashSet<>();
principals.add(new UserPrincipal(user));
for (String role : roles)
principals.add(new RolePrincipal(role));
for (String group: groups)
principals.add(new GroupPrincipal(group));
return true;
}
public boolean abort() throws LoginException
{
return true;
}
public boolean logout() throws LoginException
{
subject.getPrincipals().removeAll(principals);
principals.clear();
return true;
}
}
二;为了将此类用作新领域的LoginModule,我们必须注册一个新的org.apache.karaf.jaas.config.JaasRealm
服务并设置我们自己的登录模块。我们将此文件与CustomLoginModule
放在同一个包中。
@Component(immediate = true)
public class CustomJaasRealmService implements JaasRealm
{
public static final String REALM_NAME = "customRealm";
private AppConfigurationEntry[] configEntries;
@Activate
public void activate(BundleContext bc)
{
// create the configuration entry field using ProxyLoginModule class
Map<String, Object> options = new HashMap<>();
configEntries = new AppConfigurationEntry[1];
configEntries[0] = new AppConfigurationEntry(ProxyLoginModule.class.getName(),
LoginModuleControlFlag.SUFFICIENT, options);
// actual LoginModule class name will be passed using the options object
options.put(ProxyLoginModule.PROPERTY_MODULE, CustomLoginModule.class.getName());
// put bundle id of the LoginModule and bundlecontext of it
// (in this case, it is the same bundle)
// This is a neat trick to adapt to OSGI classloader
long bundleId = bc.getBundle().getBundleId();
options.put(ProxyLoginModule.PROPERTY_BUNDLE, String.valueOf(bundleId));
options.put(BundleContext.class.getName(), bc);
// add extra options if needed; for example, karaf encryption
// ....
}
@Override
public AppConfigurationEntry[] getEntries()
{
return configEntries;
}
// return the name and the rank of the realm
@Override
public String getName()
{
return REALM_NAME;
}
@Override
public int getRank()
{
return 0;
}
}