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

2

I'm creating an application using the demoiselle framework, but I'm encountering some issues with the security part.

I need to be automatically redirected to the login.jsf page when the user tries to access another page of the application (index.jsf, empresa.jsf, etc) without having logged in, that is, as long as the user does not login it 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:

Asdescribedabove,youonlyneedtoentertheloginpageandyouwanttoenableordisableautomaticredirectionfortheloginpageafteranattempttoaccessaprotectedresource.

Well,ItriedtoimplementthisimplementationbutIwasnotsuccessful,eventhoughItrytoaccessanotherpagewithouttheuserbeingloggedin,theloginpageisnotredirected.Iimagineyouhaveimplementedalltheclassesnecessaryfortheredirectiontowork.Belowishowmyclassesandconfigurationfilesare.

Pom.xml

<?xmlversion="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

Authenticator.java

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();
    }

}

Authorizer.java

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

}

Credentials.java

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: link

Thank you in advance for your help.

    
asked by anonymous 18.03.2015 / 20:13

1 answer

1

The settings are correct, but the authentication, authorization, and credential classes must be annotated with @SessionScoped. But you need to clarify that blocking is done on protected resources that can be classes, methods, or page components. In the example you commented, if access is made to a page that has no protected resource, it will be displayed. Because there may be parts of the public access application Here are some examples of improvements that can be made to the code you've just passed:

In the Authenticator.java class

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 log in:

@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 looks 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 the 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);
    }

}

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

    
20.03.2015 / 20:53