Redirect to login page when accessing another page without user being logged in

Asked

Viewed 1,026 times

2

I’m creating an application using the Demoiselle framework, but I’m finding some problems with the security part.

I need to be automatically redirected to the login.jsf page when the user tries to access another application page (index.jsf, company.jsf, etc.) without having logged in, that is, while the user does not log in he will not have access to any page.

According to documentation related to version 2.4.2 of Demoiselle, the framework already has this functionality as below:

inserir a descrição da imagem aqui

As described above, you only need to inform the login page and whether you want to enable or disable automatic redirection to the login page after an attempt to access a protected resource.

Well, I tried to carry out this implementation but I was not successful, even if I try to access another page without the user being logged in, there is no redirection to the login page. I imagine you’ve implemented all the classes necessary for the redirect to work. Below follows how are my classes and configuration files.

Pom.xml

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://maven.apache.org/POM/4.0.0"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

    <modelVersion>4.0.0</modelVersion>

    <groupId>br.com.djsystem</groupId>
    <artifactId>DJCloud</artifactId>
    <version>1.0.0-SNAPSHOT</version>
    <packaging>war</packaging>

    <parent>
        <groupId>br.gov.frameworkdemoiselle</groupId>
        <artifactId>demoiselle-jsf-parent</artifactId>
        <version>2.4.0</version>
    </parent>

    <dependencies>
        <dependency>
            <groupId>br.gov.frameworkdemoiselle</groupId>
            <artifactId>demoiselle-jsf</artifactId>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>br.gov.frameworkdemoiselle</groupId>
            <artifactId>demoiselle-jpa</artifactId>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.primefaces</groupId>
            <artifactId>primefaces</artifactId>
            <scope>compile</scope>
        </dependency>
        <dependency>
            <groupId>org.primefaces.extensions</groupId>
            <artifactId>all-themes</artifactId>
            <scope>compile</scope>
            <version>1.0.8</version>
        </dependency>
        <dependency>
            <groupId>br.gov.frameworkdemoiselle.component</groupId>
            <artifactId>demoiselle-junit</artifactId>
            <version>2.3.0</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>
</project>

Web.xml

<?xml version="1.0"?>
<web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
    version="3.0">

    <context-param>
        <param-name>primefaces.THEME</param-name>
        <param-value>bootstrap</param-value>
    </context-param>

    <servlet>
        <servlet-name>Faces Servlet</servlet-name>
        <servlet-class>javax.faces.webapp.FacesServlet</servlet-class>
        <load-on-startup>1</load-on-startup>
    </servlet>

    <servlet-mapping>
        <servlet-name>Faces Servlet</servlet-name>
        <url-pattern>*.jsf</url-pattern>
    </servlet-mapping>

    <security-constraint>
        <display-name>Restrict raw XHTML Documents</display-name>
        <web-resource-collection>
            <web-resource-name>XHTML</web-resource-name>
            <url-pattern>*.xhtml</url-pattern>
        </web-resource-collection>
        <auth-constraint />
    </security-constraint>
</web-app>

/WEB-INF/Beans.xml

<beans xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">

    <interceptors>
        <class>br.gov.frameworkdemoiselle.transaction.TransactionalInterceptor</class>
        <class>br.gov.frameworkdemoiselle.security.RequiredPermissionInterceptor</class>
        <class>br.gov.frameworkdemoiselle.security.RequiredRoleInterceptor</class>
        <class>br.gov.frameworkdemoiselle.exception.ExceptionHandlerInterceptor</class>
    </interceptors>

</beans>

login.xhtml

<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
    xmlns:p="http://primefaces.org/ui" xmlns:h="http://java.sun.com/jsf/html"
    xmlns:ui="http://java.sun.com/jsf/facelets">

<h:head>
    <title>#{messages['main.app.title']}</title>
</h:head>

<h:body>
    <h:form>  
        <p:growl id="messages"/>
        <p:menubar style="font-weight: bold; font-size: small">
            <p:menuitem value="Portal DJCloud" url="#" />
            <f:facet name="options">
                <p:outputLabel for="login" value="Usuário: " />
                <p:inputText id="login" style="margin-right:10px" value="#{credenciais.username}" />
                <p:outputLabel for="senha" value="Senha: " />
                <p:inputText id="senha" style="margin-right:10px" value="#{credenciais.password}" />
                <p:commandButton value="Login" icon="ui-icon-locked" action="#{securityContext.login()}" />
            </f:facet>
        </p:menubar>
    </h:form>
</h:body>
</ui:composition>

Demoiselle.properties

frameworkdemoiselle.security.enabled=true frameworkdemoiselle.security.authorizer.class=br.com.djsystem.djcloud.security.Authorizer frameworkdemoiselle.security.Authenticator.class=br.com.djsystem.djcloud.security.Authenticator frameworkdemoiselle.security.login.page=/login.xhtml frameworkdemoiselle.security.redirect.after.login=/index.xhtml frameworkdemoiselle.security.redirect.after.logout=/login.xhtml frameworkdemoiselle.security.redirect.enabled=true

Java authenticator.

package br.com.djsystem.djcloud.security;

import javax.inject.Inject;

import br.com.djsystem.djcloud.security.Credenciais;
import br.gov.frameworkdemoiselle.security.Authenticator;
import br.gov.frameworkdemoiselle.security.User;
import br.gov.frameworkdemoiselle.util.ResourceBundle;

public class Autenticador implements Authenticator {

    private static final long serialVersionUID = 1L;

    @Inject
    private Credenciais credenciais;

    @Inject
    private ResourceBundle bundle;

    @Override
    public void authenticate() throws Exception {
        if (!credenciais.getUsername().equals("ricardo") || !credenciais.getPassword().equals("ricardo")) {
            throw new RuntimeException(bundle.getString("usuarioNaoAutenticado"));
        }

    }

    @Override
    public User getUser() {
        return new User() {

            private static final long serialVersionUID = 1L;

            @Override
            public void setAttribute(Object arg0, Object arg1) {
                // TODO Auto-generated method stub

            }

            @Override
            public String getId() {
                return credenciais.getUsername();
            }

            @Override
            public Object getAttribute(Object arg0) {
                // TODO Auto-generated method stub
                return null;
            }
        };
    }

    @Override
    public void unauthenticate() throws Exception {
        credenciais.clear();
    }

}

Java authorizer.

package br.com.djsystem.djcloud.security;

import br.gov.frameworkdemoiselle.security.Authorizer;

public class Autorizador implements Authorizer {

    private static final long serialVersionUID = 1L;

    @Override
    public boolean hasPermission(String arg0, String arg1) throws Exception {
        return false;
    }

    @Override
    public boolean hasRole(String arg0) throws Exception {
        return false;
    }

}

Java credentials.

package br.com.djsystem.djcloud.security;

import java.io.Serializable;

import br.gov.frameworkdemoiselle.stereotype.ViewController;

@ViewController
public class Credenciais implements Serializable {

    private static final long serialVersionUID = 1L;

    private String username;
    private String password;

    public void clear() {
        this.username = null;
        this.password = null;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}

If you need to look at the entire project, the download link is this: https://www.dropbox.com/s/7z76co3usf1l6gv/Projeto_exemplo.7z?dl=0

Thanks in advance for possible help.

1 answer

1


Settings are correct, but authentication, authorization and credential classes should be annotated with @Sessionscoped. But it is necessary to clarify that blocking is done on protected resources that can be classes, methods, or components of pages. In the example you commented, if access is done on a page that has no protected resource it will be presented. Because there may be parts of the public access application Below are some examples of improvements that can be made in the code you passed:

In the Authenticator class.java

import javax.enterprise.context.SessionScoped;
import javax.inject.Inject;

import br.com.djsystem.djcloud.security.Credenciais;
import br.gov.frameworkdemoiselle.security.AuthenticationException;
import br.gov.frameworkdemoiselle.security.Authenticator;
import br.gov.frameworkdemoiselle.security.User;
import br.gov.frameworkdemoiselle.util.ResourceBundle;

@SessionScoped
public class Autenticador implements Authenticator {

    private static final long serialVersionUID = 1L;

    @Inject
    private Credenciais credenciais;

    @Inject
    private ResourceBundle bundle;

    private static boolean authenticated=false;

    @Override
    public void authenticate() throws Exception {
        if (!credenciais.getUsername().equals("ricardo") || !credenciais.getPassword().equals("ricardo")) {
        throw new AuthenticationException(bundle.getString("usuarioNaoAutenticado"));
    }else{
        authenticated = true;
    }
}

@Override
public User getUser() {
    if (authenticated) {
        return new User() {

            private static final long serialVersionUID = 1L;

            @OverrideA autenticação pode ter essa melhorias. podem ser melhoradas assim:
            public void setAttribute(Object arg0, Object arg1) {
                // TODO Auto-generated method stub
            }

            @Override
            public String getId() {
                return credenciais.getUsername();
            }

            @Override
            public Object getAttribute(Object arg0) {
                // TODO Auto-generated method stub
                return null;
            }               
        };
    }else{
        return null;
    }
}

@Override
public void unauthenticate() throws Exception {
    credenciais.clear();
    authenticated = false;
}

}

You need to implement a Managedbean to run the login:

@ViewController
@NextView("./index.jsf")
public class LoginMB extends AbstractPageBean{

    private static final long serialVersionUID = 1L;

    private String usuario  = new String();
    private String senha = new String();

    @Inject
    private Credenciais credenciais;

    @Inject
    private SecurityContext securityContext;

    @Inject
    private MessageContext messageContext;

    public String doLogin() {
        try {
            credenciais.setUsername(this.getUsuario());
            credenciais.setPassword(this.senha);
            securityContext.login();
            return getNextView();
        }catch (Exception e) {
            messageContext.add(e.getMessage());
            return "";
        }       
    }

    public void setUsuario(String usuario) {
    this.usuario = usuario;
    }

    public String getUsuario() {
        return usuario;
    }

    public void setSenha(String senha) {
        this.senha = senha;
    }

    public String getSenha() {
        return senha;
    }

    public void doLogout() {
        securityContext.logout();
    }
}

Your login page would look like this:

<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui" xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">

   <h:head>
        <title>#{messages['main.app.title']}</title>
    </h:head>

    <h:body>
        <h:form>  
            <p:growl id="messages"/>
            <p:menubar style="font-weight: bold; font-size: small">
            <p:menuitem value="Portal DJCloud" url="#" />
            <f:facet name="options">
                <p:outputLabel for="login" value="Usuário: " />
            <p:inputText id="login" style="margin-right:10px" value="#{loginMB.usuario}"  required="true"/>
                <p:outputLabel for="senha" value="Senha: " />
                <h:inputSecret id="senha" value="#{loginMB.senha}" style="margin-right:10px"  required="true"/>
                <p:commandButton value="Login" icon="ui-icon-locked" action="#{loginMB.doLogin()}" />
           </f:facet>
    </p:menubar>
    </h:form>
</h:body>
</ui:composition>

You can protect the "reserved" content of pages such as the menu:

<ui:composition xmlns="http://www.w3.org/1999/xhtml" xmlns:f="http://java.sun.com/jsf/core"
xmlns:p="http://primefaces.org/ui" xmlns:h="http://java.sun.com/jsf/html"
xmlns:ui="http://java.sun.com/jsf/facelets">

    <h:form >
        <p:menubar style="font-weight: bold; font-size: small"  rendered="#{securityContext.loggedIn}">
            <p:submenu label="#{messages['menu.bookmark']}">
                <p:menuitem value="#{messages['menu.menuitem.new']}"  url="/bookmark_edit.jsf" />
                <p:menuitem value="#{messages['menu.menuitem.list']}" url="/bookmark_list.jsf" />
            </p:submenu>

       <f:facet name="options">
            <p:inputText style="margin-right:10px" placeholder="Procure"/>
            <p:commandButton url="http:/login.jsf" value="Logout" icon="ui-icon-extlink" action="#{securityContext.logout}" />
       </f:facet>
        </p:menubar>
    </h:form>

</ui:composition>

And also protect methods in business class:

@BusinessController
public class BookmarkBC extends DelegateCrud<Bookmark, Long, BookmarkDAO> {

    private static final long serialVersionUID = 1L;


    @Override
    @RequiredPermission(resource = "bookmark", operation = "insert")
    public Bookmark insert(Bookmark bookmark) {
        return super.insert(bookmark);
    }

    @Override
    @RequiredPermission(resource = "bookmark", operation = "delete")
    public void delete(Long id) {
        super.delete(id);
    }

    @Override
    @RequiredPermission(resource = "bookmark", operation = "delete")
    public void delete(List<Long> ids) {
        super.delete(ids);
    }

    @Override
    @RequiredPermission(resource = "bookmark", operation = "findAll")
    public List<Bookmark> findAll() {
        return super.findAll();  
    }

    @Override
    @RequiredPermission(resource = "bookmark", operation = "load")
    public Bookmark load(Long id) {
        return super.load(id);
    }

    @Override
    @RequiredPermission(resource = "bookmark", operation = "update")
    public Bookmark update(Bookmark bookmark) {
        return super.update(bookmark);
    }

}

This way when there is attempt to access some page that accesses some protected method, it will be directed to the login page.

Browser other questions tagged

You are not signed in. Login or sign up in order to post.