Java / WildFly / MongoDB / JAAS - Аутентификация всегда возвращает 403 - Запрещено

1

Я создал пользовательский LoginModule для аутентификации пользователей, присутствующих в коллекциях mongoDB. В моем случае мне нужна одна роль на странице... Я уже использовал аутентификацию JAAS с JSF, но в этом случае она работает не так, как ожидалось... Она всегда возвращает ошибку 403 (Forbidden). Отображение URL-адресов, по-видимому, в порядке.

Что моя иерархия страниц:

  • приложение <-root
    • страницы
      • мои защищенные страницы (одна роль на странице)
    • login.html
    • login_error.html
    • index.html

Следуйте моим настройкам:

JBoss-web.xml

<jboss-web>
    <security-domain>nfceSecurityDomain</security-domain>
    <disable-audit>true</disable-audit>
</jboss-web>

web.xml

<session-config>
  <session-timeout>30</session-timeout>
</session-config>

<login-config>
     <auth-method>FORM</auth-method>
     <form-login-config>
          <form-login-page>/app/login.html</form-login-page>
          <form-error-page>/app/login_error.html</form-error-page>
     </form-login-config>
</login-config>

<security-role>
   <role-name>VISUALIZAR_NOTAS</role-name>
</security-role>
<security-role>
   <role-name>GESTAO_CERTIFICADO</role-name>
</security-role>
<security-role>
   <role-name>GESTAO_EMPRESA</role-name>
</security-role>
<security-role>
   <role-name>DOWNLOAD_XML</role-name>
</security-role>
<security-role>
   <role-name>INUTILIZACAO</role-name>
</security-role>

<security-constraint>
    <web-resource-collection>
         <web-resource-name>index</web-resource-name>
         <url-pattern>/app/index.html</url-pattern>
         <http-method>POST</http-method>
         <http-method>GET</http-method>
         <http-method>PUT</http-method>
         <http-method>DELETE</http-method>
    </web-resource-collection>
    <auth-constraint>
            <role-name>VISUALIZAR_NOTAS</role-name>
    </auth-constraint>
</security-constraint>
<security-constraint>
    <web-resource-collection>
         <web-resource-name>orderList</web-resource-name>
         <url-pattern>/app/pages/orderlist.html</url-pattern>
         <http-method>POST</http-method>
         <http-method>GET</http-method>
         <http-method>PUT</http-method>
         <http-method>DELETE</http-method>
    </web-resource-collection>
    <auth-constraint>
         <role-name>VISUALIZAR_NOTAS</role-name>
    </auth-constraint>
</security-constraint>
<security-constraint>
   <web-resource-collection>
       <web-resource-name>certificateConfigurations</web-resource-name>
       <url-pattern>/app/pages/certifiedlist.html</url-pattern>
        <http-method>POST</http-method>
        <http-method>GET</http-method>
        <http-method>PUT</http-method>
        <http-method>DELETE</http-method>
   </web-resource-collection>
   <auth-constraint>
       <role-name>GESTAO_CERTIFICADO</role-name>
   </auth-constraint>
</security-constraint>
<security-constraint>
   <web-resource-collection>
       <web-resource-name>enterpriseConfigurations</web-resource-name>
       <url-pattern>/app/pages/enterpriselist.html</url-pattern>
        <http-method>POST</http-method>
        <http-method>GET</http-method>
        <http-method>PUT</http-method>
        <http-method>DELETE</http-method>
   </web-resource-collection>
   <auth-constraint>
       <role-name>GESTAO_EMPRESA</role-name>
   </auth-constraint>
</security-constraint>
<security-constraint>
   <web-resource-collection>
       <web-resource-name>xmlDownload</web-resource-name>
       <url-pattern>/app/pages/orderdownload.html</url-pattern>
        <http-method>POST</http-method>
        <http-method>GET</http-method>
        <http-method>PUT</http-method>
        <http-method>DELETE</http-method>
   </web-resource-collection>
   <auth-constraint>
       <role-name>DOWNLOAD_XML</role-name>
   </auth-constraint>
</security-constraint>
<security-constraint>
   <web-resource-collection>
       <web-resource-name>invalidate</web-resource-name>
       <url-pattern>/app/pages/orderInvalidate.html</url-pattern>
        <http-method>POST</http-method>
        <http-method>GET</http-method>
        <http-method>PUT</http-method>
        <http-method>DELETE</http-method>
   </web-resource-collection>
   <auth-constraint>
       <role-name>INUTILIZACAO</role-name>
   </auth-constraint>
</security-constraint>

standalone.xml

<subsystem xmlns="urn:jboss:domain:security:1.2">
            <security-domains>
                <security-domain name="nfceSecurityDomain" cache-type="default">
                    <authentication>
                        <login-module code="br.com.ciss.nfce.security.JAASLoginModule" flag="required"/>
                    </authentication>
                </security-domain>
            </security-domains>
        </subsystem>

И вот моя реализация LoginModule, чтобы получить пользователя и роли от MongoDB:

public class JAASLoginModule implements LoginModule {

    private static final Logger LOG = Logger.getLogger(JAASLoginModule.class);

    private Subject subject;
    private CallbackHandler callbackHandler;
    private Map sharedState;
    private Map options;

    private boolean succeeded = false;
    private boolean commitSucceeded = false;

    private String username = null;
    private String _idUser = "";
    private char[] password = null;

    private Principal userPrincipal = null;
    private Principal passwordPrincipal = null;

    private ConnectionMongoUtil connectionMongoUtil;

    public JAASLoginModule() {
        super();
    }

    @Override
    public void initialize(Subject subject, CallbackHandler callbackHandler,
            Map<String, ?> sharedState, Map<String, ?> options) {
        this.subject = subject;
        this.callbackHandler = callbackHandler;
        this.sharedState = sharedState;
        this.options = options;
    }

    @Override
    public boolean login() throws LoginException {

        if (callbackHandler == null) {
            throw new LoginException("Error: no CallbackHandler available "
                    + "to garner authentication information from the user");
        }
        Callback[] callbacks = new Callback[2];
        callbacks[0] = new NameCallback("username");
        callbacks[1] = new PasswordCallback("password: ", false);

        try {
            callbackHandler.handle(callbacks);
            username = ((NameCallback) callbacks[0]).getName();
            password = ((PasswordCallback) callbacks[1]).getPassword();

            if (username == null || password == null) {
                LOG.error("Callback handler does not return login data properly");
                throw new LoginException(
                        "Callback handler does not return login data properly");
            }

            if (isValidUser()) { // validate user.
                succeeded = true;
                return true;
            }
        } catch (IOException e) {
            e.printStackTrace();
        } catch (UnsupportedCallbackException e) {
            e.printStackTrace();
        }

        return false;
    }

    @Override
    public boolean commit() throws LoginException {
        if (succeeded == false) {
            return false;
        } else {
            userPrincipal = new JAASUserPrincipal(username);
            if (!subject.getPrincipals().contains(userPrincipal)) {
                subject.getPrincipals().add(userPrincipal);
                LOG.debug("User principal added:" + userPrincipal);
            }
            passwordPrincipal = new JAASPasswordPrincipal(new String(password));
            if (!subject.getPrincipals().contains(passwordPrincipal)) {
                subject.getPrincipals().add(passwordPrincipal);
                LOG.debug("Password principal added: " + passwordPrincipal);
            }

            List<String> roles = getRoles();
            for (String role : roles) {
                Principal rolePrincipal = new JAASRolePrincipal(role);
                if (!subject.getPrincipals().contains(rolePrincipal)) {
                    subject.getPrincipals().add(rolePrincipal);
                    LOG.debug("Role principal added: " + rolePrincipal);
                }
            }

            commitSucceeded = true;
            LOG.info("Login subject were successfully populated with principals and roles");
            return true;
        }
    }

    @Override
    public boolean abort() throws LoginException {
        if (succeeded == false) {
            return false;
        } else if (succeeded == true && commitSucceeded == false) {
            succeeded = false;
            username = null;
            if (password != null) {
                password = null;
            }
            userPrincipal = null;
        } else {
            logout();
        }
        return true;
    }

    @Override
    public boolean logout() throws LoginException {
        subject.getPrincipals().remove(userPrincipal);
        succeeded = false;
        succeeded = commitSucceeded;
        username = null;
        if (password != null) {
            for (int i = 0; i < password.length; i++) {
                password[i] = ' ';
                password = null;
            }
        }
        userPrincipal = null;
        return true;
    }

    private boolean isValidUser() throws LoginException {

        try {
            BasicDBObject search = new BasicDBObject();
            search.put("email", username);
            connectionMongoUtil = new ConnectionMongoUtil();
            DBObject user = connectionMongoUtil.getCollection("User").findOne(search);

            if (user == null){
                LOG.debug("USUÁRIO NÃO LOCALIZADO!");
                return false;
            }else{
                if ( new String(password).equals(user.get("password"))){
                    _idUser = user.get("_id").toString();
                    return true;
                }else{
                    LOG.debug("SENHA INVÁLIDA PARA O USUÁRIO " + username);
                }
            }

            return false;
        } catch (Exception e) {
            LOG.error("Error when loading user " + username + " from the database \n", e);
        }

        return false;
    }

    /**
     * Returns list of roles assigned to authenticated user.
     * 
     * @return
     */
    private List<String> getRoles() {
        BasicDBObject search = new BasicDBObject();
        search.put("_idUser", _idUser);
        DBObject userModules = connectionMongoUtil.getCollection("UserModules").findOne(search);
        String jsonArrayModules = userModules.get("_idModules").toString();

        String[] modules = null;
        try {
            modules = new ObjectMapper().readValue(jsonArrayModules, String[].class);
        } catch (IOException e) {
            e.printStackTrace();
        }

        List<String> modulesList = new ArrayList<String>();
        for (String _idModule : modules) {
            DBObject module = connectionMongoUtil.getCollection("Module").findOne(new BasicDBObject("_id", new ObjectId(_idModule)));
            if (module != null){
                modulesList.add(module.get("name").toString());
            }
        }

        return modulesList;
    }
}

Я добавил следующее свойство в standalone.xml, чтобы увидеть журналы, созданные JAAS, и не имеет журнала ошибок...

<logger category="org.jboss.security">
    <level name="ALL"/>
</logger>

В моих коллекциях MongoDB я добавил все роли своему пользователю, и когда я пытаюсь войти в систему, я могу войти в систему, но все страницы заблокированы, возвращая ошибку 403.

Кто-нибудь может мне помочь? Может быть, это всего лишь небольшая деталь, вызывающая ошибку 403...

Спасибо за внимание!

  • 0
    Вы пробовали регистрировать фактический используемый запрос MongoDB и возвращаемое значение? Если вы не уверены, куда добавить отладочную информацию в JAAS, вы можете попробовать использовать профилировщик базы данных MongoDB на уровне 2 (все запросы, а не только медленные запросы).
  • 0
    Привет, парень, спасибо за ваш ответ ... Я думаю, что проблема не в запросах mongoDB, потому что я установил пользователя и роли в JAASLoginModule, и произошла та же ошибка. Я думаю, что ошибка в конфигурации JBoss ...
Показать ещё 1 комментарий
Теги:
wildfly-8
jaas
form-authentication

3 ответа

0
Лучший ответ

Единственный способ разрешить эту ситуацию - это изменение JAAS по Spring Security :)

0

Я знаю, что это старая нить, но все же без хорошего решения.

У меня была такая же проблема...

В некотором контексте: у меня было "здоровое" Java-приложение, использующее JAAS (прямое выполнение javax.security.auth.spi.LoginModule), плавно выполняющееся на Tomcat7. Затем на сцену пришли требования заказчика: "Он должен работать на JBoss 7.1.1" WTF? Даже небольшая версия и патч!?!

Hands On: я сделал всю конфигурацию, имел некоторые недостатки с кодом Java 8 и JAX-RS, но это еще одна история, в конце концов мое приложение было успешно развернуто в JBoss 7.1.1.

Проблема: я мог видеть на консоли, что логин был успешным, но все запросы возвращали HTTP 403.

При отладке всех Принципов (CallerPrincipal и UserRoles) были в порядке.

Кроме того, у меня есть один абстрактный BaseServlet для оркестровки и который все запросы должны проходить, но HTTP 403 возникла до его достижения...

Решение. Поэтому я заметил, что вся документация JBoss, касающаяся JAAS, советует разработчикам расширять свои настраиваемые LoginModules, поэтому я начал копать.

Org.jboss.security.auth.spi.AbstractServerLoginModule использует то, что они называют "стандартным шаблоном использования JBossSX для хранения идентификаторов и ролей".

Я не стал так подробно объяснять шаблон, но я реализовал "JBossWebRealm", который завершает процесс аутентификации в стороне контейнера, ожидает реализации java.security.acl.Group с именем "Роли", содержащим всех Принципов (CallerPrincipal и UserRoles) в качестве членов (членство в JAASRealm).

Этот объект используется для проверки безопасности.

Конец истории, я добавил этот метод к моей реализации LoginModule:

public boolean commit() throws LoginException {

    // some validation code here

    Set<Principal> principals = subject.getPrincipals();

    // ensure principals contains (CallerPrincipal and UserRoles)

    createRolesGroup(principals);

    return true;
}

private void createRolesGroup(Set<Principal> principals) {

    // Thee java.security.acl.Group implementation
    SecurityGroup rolesGroup = new SecurityGroup("Roles");

    Iterator<Principal> iter = principals.iterator();

    while(iter.hasNext()) {
        Object principal = iter.next();
        if(!(principal instanceof Group)){
        rolesGroup.addMember((Principal)principal);
    }

    principals.add(rolesGroup);
}

И работает как шарм.

Надеюсь, поможет.

0

Вы пробовали развернуть свой модуль в wildfly http://www.mastertheboss.com/jboss-server/jboss-security/configuring-a-mongodb-login-module

  • 0
    К сожалению, у меня нет времени, чтобы сделать это в моей работе. Когда у меня будет время, я проведу этот тест, а затем сообщу вам о результате. Спасибо!

Ещё вопросы

Сообщество Overcoder
Наверх
Меню