Собственный Security Realm в GlassFish

в 8:13, , рубрики: glassfish, java, security, метки: , ,

Ни для кого не секрет что сервера приложений существуют для того чтобы снять некоторую часть работы с разработчика и возложить её на уже готовые механизмы. В частности механизм аутентификации в сервере приложений Glassfish можно организовать с помощью так называемых Security Realms. Существуют несколько встроенных вариантов, такие как аутентификация через СУБД, LDAP, PAM, Certificate и обычное чтение из файла. Однако они могут нас не устроить ввиду своей ограниченности (LDAP, например, может работать только с одним наперед заданным доменом). Поэтому мы и рассмотрим создание собственного security realm’а.

Custom security realm состоит минимум из двух классов. Один из которых расширяет класс AppservRealm (com.sun.appserv.security.AppservRealm), а второй соответственно AppservPasswordLoginModule (com.sun.appserv.security.AppservPasswordLoginModule). Для получения com.sun.appserv.security.* нужно импортировать в качестве библиотеки /glassfish/modules/security.jar

package ru.khmb.security;

import com.sun.appserv.security.AppservRealm;
import com.sun.enterprise.security.auth.realm.BadRealmException;
import com.sun.enterprise.security.auth.realm.InvalidOperationException;
import com.sun.enterprise.security.auth.realm.NoSuchRealmException;
import com.sun.enterprise.security.auth.realm.NoSuchUserException;
import java.util.Enumeration;
import java.util.Properties;
import java.util.Vector;

public class Realm extends AppservRealm {

    private static final String PARAM_JAAS_CONTEXT = "jaas-context";
    private static final String GROUP_ALL = "Authenticated";

    @Override
    public void init(Properties properties)
            throws BadRealmException, NoSuchRealmException {
        String propJaasContext = properties.getProperty(PARAM_JAAS_CONTEXT);
        if (propJaasContext != null) {
            setProperty(PARAM_JAAS_CONTEXT, propJaasContext);
        }
    }

    @Override
    public String getAuthType() {
        return "KHMB Realm";
    }

    @Override
    public Enumeration getGroupNames(String user)
            throws InvalidOperationException, NoSuchUserException {
        Vector vector = new Vector();
        vector.add(GROUP_ALL);
        return vector.elements();
    }
}

В классе realm'а необходимо переопредели методы получения типа аутентификации (обычно это название realm'а) и получение групп пользователя по его имени — в данной статье мы умышленно упускаем обзор Java EE авторизации.
Соответственно здесь мы и можем реализовать гибкость механизма в получении групп по имени пользователя, например из СУБД. В данном примере используется одна группа, которая показывает что пользователь прошел аутентификацию. Property jaas-context указывается здесь чтобы связать данный класс со следующим.

package ru.khmb.security;

import com.sun.appserv.security.AppservPasswordLoginModule;
import java.util.Enumeration;
import java.util.LinkedList;
import java.util.List;
import javax.security.auth.login.LoginException;

public class LoginModule extends AppservPasswordLoginModule {

    @Override
    protected void authenticateUser() throws LoginException {
        if (!(_currentRealm instanceof Realm)) {
            throw new LoginException("Realm not KHMBRealm");
        }

        Realm realm = (Realm) _currentRealm;

        authenticate(_username, _password);

        Enumeration enumeration = null;
        List<String> authenticatedGroups = new LinkedList();
        try {
            enumeration = realm.getGroupNames(_username);
        } catch (Exception e) {
            throw new LoginException("Get groups exception");
        }
        for (int i = 0; enumeration != null && enumeration.hasMoreElements(); i++) {
            authenticatedGroups.add((String) enumeration.nextElement());
        }

        commitUserAuthentication(authenticatedGroups.toArray(new String[0]));
    }

    private static void authenticate(String login, String password) throws LoginException {
        try {
            LDAP.authenticate(login, password);
        } catch (Exception e) {
            throw new LoginException("Authenticate exception:" + e.getMessage());
        }
    }
}

В данном классе необходимо реализовать метод аутентификации. Он состоит из получения и проверки использующего его realm'а, проверки правильности введенных логина и пароля (либо других реквизитов) и наконец, получения и передачи групп пользователя.
Скомпилированные классы кладем в директорию <домен glassfish>/lib/classes
Также мы должны определить что наш AppservPasswordLoginModule относится к определенному контексту. Нужно отредактировать файл <домен glassfish>/config/login.conf добавив «ссылку»:

KHMBRealm {
       ru.khmb.security.LoginModule required;
};

В котором мы определяем контекст и ссылаемся на необходимость модуля.

Смело запускаем/перегружаем наш сервер приложений и открываем GUI администратора.
Создаем новый Security Realm. Теперь нам не нужно выбирать класс из списка, а вводим полный класс реалма: ru.khmb.security.Realm. Не забываем указать опцию jaas-context которая связывает наш realm с модулем аутентификации через контекст указанный в файле login.conf, т.е. в нашем случаи jaas-context = KHMBRealm

Всё, теперь можно пользоваться Realm'ом.

При реализации механизма источником была запись в блоге.

Автор: wisd

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js