如何将自定义LoginModule添加到Karaf Jaas安全框架?

时间:2014-11-28 08:47:45

标签: osgi jaas karaf

我想在Karaf Jaas框架中添加一个自定义的LoginModule,并创建一个将使用它的新领域。

我该怎么做?

1 个答案:

答案 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;
    }   
}