Пользовательский модуль входа в Wildfly 8, получающий доступ к параметрам HttpServletRequest

Я изучаю возможность использования пользовательского модуля входа в систему wildfly.

Клиент передаст идентификатор мобильного устройства на сервер как часть входа в систему. Я проверю правильность имени пользователя и пароля обычным способом, затем мне нужно будет убедиться, что мобильное устройство одобрено для использования службы.

Идея состоит в том, что у меня будет спокойный метод входа в веб-службу, который вызывает HttpServletRequest.login(u, p).

Как получить идентификатор мобильного устройства внутри модуля входа в HttpServletRequest?

Я мог бы войти в систему, и если это удастся, проверьте идентификатор устройства в веб-сервисе, и если это не будет одобрено, выйдите из системы. Но это кажется довольно грязным.

Каков правильный способ сделать это?

ИЗМЕНИТЬ

ОТЗЫВ: Я сделал так, как предложил Крис. Я реализовал свою собственную версию CallBackHandler и реализацию интерфейса обратного вызова, внутри метода входа в мой модуль входа я делаю следующее:

public boolean login() throws LoginException {

        boolean login = super.login();

        if (login) {

            UuidCallback uuidCallback = new UuidCallback();

            try {

                super.callbackHandler.handle(new Callback[]{uuidCallback});

            } catch (Exception e) {

                LoginException le = new LoginException("Failed to get uuid");
                le.initCause(e);

                throw le;
            }

            System.out.print("Device UUID: "+uuidCallback.getUuid());
    }

    return login;
}

Внутри метода входа в веб-службу:

@Path("/login")
@Produces({ "application/json" })
public class LoginWebService {

    @POST
    public Response login(@Context HttpServletRequest request) throws LoginException {

        CallbackHandler callbackHandler = new MyCallbackHandler(request.getParameter("username"), request.getParameter("password"), request.getParameter("uuid"));

        Subject subject = new Subject();
        LoginContext loginContext = new LoginContext("securityDomain", new subject, callbackHandler);

        loginContext.login();

        MyPrincipal principal = subject.getPrincipals(MyPrincipal.class).iterator().next();
    }
}

Вы также можете просто установить uuid в обработчике обратного вызова, а затем вызвать getUUID() в обработчике обратного вызова внутри метода LoginModule.login. Но я решил пойти с дизайном, хотя он не совсем имеет смысл для меня.

Я все еще получал 403 при входе в систему и пытался получить доступ к защищенным ресурсам, оказалось, что если auth-constraint/role-name равно *, вы должны указать хотя бы один security-role.

<login-config>
    <auth-method>FORM</auth-method>
    <realm-name>mydomain</realm-name>
</login-config>
<security-constraint>
    <web-resource-collection>
        <web-resource-name>rest</web-resource-name>
        <url-pattern>/rest/app/*</url-pattern>
    </web-resource-collection>
    <auth-constraint>
        <role-name>*</role-name>
    </auth-constraint>
</security-constraint>
<!-- after login there is a 403 on protected resources if no role and role-name * -->
<security-role>
    <role-name>user</role-name>
</security-role>

У всех моих пользователей есть роль пользователя, которая дает им доступ. Я смог заставить его работать, исключив security-role, но тогда auth-constraint/role-name должна быть установлена ​​буквальная роль, в моем случае: «пользователь»


person Rian    schedule 04.12.2015    source источник


Ответы (2)


Я бы предложил создать LoginContext и передать реализацию CallbackHandler. В обработчике обратного вызова учитывайте дополнительное свойство UUID.

Хотя этот код работает для меня, вам нужно будет обновить его, чтобы учесть дополнительное свойство UUID.

public class NamePasswordCallbackHandler implements CallbackHandler {
    private final String username;
    private final String password;

    private NamePasswordCallbackHandler(String username, String password) {
        this.username = username;
        this.password = password;
    }

    public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException {
        for (Callback current : callbacks) {
            if (current instanceof NameCallback) {
                ((NameCallback) current).setName(username);
            } else if (current instanceof PasswordCallback) {
                ((PasswordCallback) current).setPassword(password.toCharArray());
            } else {
                throw new UnsupportedCallbackException(current);
            }
        }
    }
}

Я создал собственную реализацию объекта Configuration (показан ниже как JBossJaasConfiguration).

Затем перейдите через этот обработчик обратного вызова в свой LoginContext:

CallbackHandler cbh = new NamePasswordCallbackHandler(username, password);
Configuration config = new JBossJaasConfiguration("mysqldomain");

LoginContext loginContext = new LoginContext("mycontext", new Subject(), cbh, config);
loginContext.login();

Свойство «mysqldomain» относится к имени домена безопасности в вашем файле standalone.xml.

<subsystem xmlns="urn:jboss:domain:security:1.2">
    <security-domains>
        <security-domain name="mysqldomain" cache-type="default">
             <authentication>
                  <login-module code="com.soccerx.security.DatabaseServerLoginRealm" flag="required">
                     <module-option name="dsJndiName" value="java:jboss/datasources/SoccerSoftwareDS"/>
                     <module-option name="principalsQuery" value="select userId, tenantId, password, salt from User where username=? and StatusId != 2"/>

            <module-option name="rolesQuery" value="select Role, 'Roles' from User where Username=?"/>
                    <module-option name="password-stacking" value="useFirstPass"/>
                    <module-option name="principalClass" value="com.soccerx.security.DatabasePrincipal"/>
                </login-module>
            </authentication>
        </security-domain>
    <security-domains>
</subsystem>

Хотя это не полное решение для ваших нужд, я ожидаю, что вы можете изменить его, чтобы обеспечить сбой входа в систему, если UUID не совпадает.

Примечание. Вам нужно будет учесть это в вашем CustomDatabaseLoginRealm, как определено в вашем standalone.xml. Это означает доступ к имени пользователя/паролю/uuid и сравнение его со значениями в базе данных.

Дополнительную документацию см. здесь

person Chris Ritchie    schedule 04.12.2015
comment
Чтобы подтвердить, буду ли я создавать LoginContext и вызывать логин из моего метода входа в веб-службу? - person Rian; 05.12.2015
comment
Да, точно. Также создайте объект MobileIdCallback. - person Chris Ritchie; 07.12.2015

Вместо того, чтобы вызывать метод HttpServletRequest.login() непосредственно из веб-службы покоя, вы можете настроить домен безопасности в Wildfly.

Этот домен безопасности должен быть указан в элементе login-config вашего веб-приложения web.xml с ограничением безопасности, чтобы включить JAAS

Вот пример web. xml, который объявляет ограничение безопасности и конфигурацию входа (с методом аутентификации BASIC)

И пример конфигурации Wildfly standalone.xml для конфигурации security-domain с использованием стандартного предоставленного модуля входа в базу данных, а не пользовательского:

<security-domain name="securityDomain" cache-type="default">
    <authentication>
        <login-module code="Database" flag="required">
            <module-option name="dsJndiName" value="java:/TestDS"/>
            <module-option name="principalsQuery" value="select password from User where login = ? and (disabled is null or disabled = 0) and activated = 1"/>
            <module-option name="rolesQuery" value="select name,'Roles' from Role r, User_Role ur, User u where u.login=? and u.id = ur.userId and r.id = ur.roleId"/>
            <module-option name="hashAlgorithm" value="SHA-256"/>
            <module-option name="hashEncoding" value="base64"/>
            <module-option name="unauthenticatedIdentity" value="guest"/>
        </login-module>
    </authentication>
</security-domain>

Затем в вашем ресурсе REST вам просто нужно использовать аннотации @RolesAllowed или @PermitAll, чтобы ограничить доступ или не выполнять также авторизацию.

person Rémi Bantos    schedule 04.12.2015