Showing posts with label User. Show all posts
Showing posts with label User. Show all posts

Tuesday, 2 April 2013

Creating A Customized Spring User & Persistence

This post explains how to create a customized Spring user and persistence mechanism for authentication. The code is available at GitHub in the Spring-MVC-Customized-User directory.

Things To Take Into Consideration

Before creating a customized user, we need to remind what a user is in Spring. We know from here that a user is an implementation of the UserDetails interface. Spring security also requires a loading mechanism, as an implementation of the UserDetailsService interface. To keep this example simple, we are not going to implement login/logout or other security features.

The UserDetails interface is a bit incomplete in order to define a user in a real application. It defines getters and no setters. It is not a big deal, but the real pain is that the username (a string) is considered as 'the' key. Most software developers will prefer a long id.

To solve these issues, we define a PracticalUser interface:
public interface PracticalUserDetails
        extends UserDetails, CredentialsContainer {

    long getId();

    void setPassword(String password);

    void setAccountExpired(boolean b);

    void setAccountLocked(boolean b);

    void setCredentialsExpired(boolean b);

    void setEnabled(boolean b);

    void setAuthorities(
        Collection<? extends GrantedAuthority> authorities);

}
Typically, one would use JPA annotations on the implementation bean and save it in a database in a real application. However, for this example, the DAO will register users in an in-memory map as described further.

The UserDetailsService interface does not provide a get user per name or id, which is necessary for an administrator (for example). More, it does not allow to retrieve all existing users' id and name, or to update or insert users, or even to delete them.

Therefore, we create a PracticalUserDetailsService interface to solve these issues:
public interface PracticalUserDetailsService
        extends UserDetailsService {

    Set<PracticalUserDetailsDAO.UserIdentifiers> getUsers();

    void deleteUser(long id);

    void upsertUser(PracticalUserDetails user);

    PracticalUserDetails getUser(long id);

    PracticalUserDetails getUser(String username);

}
The corresponding implementation is called PracticalUserDetailsServiceInMemory for this example.

In-Memory DAO

To keep this example simple, we define a simple PracticalUserDetailsDAO:
public interface PracticalUserDetailsDAO<U extends PracticalUserDetails> {

    void create(U user);

    boolean contains(U user);

    U read(String username);

    U read(long id);

    void update(U user);

    void delete(String username);

    void delete(long id);

    interface UserIdentifiers {
        long getId();
        String getUsername();
    }

    Set<UserIdentifiers> getUsers();

}
We also define a special user id and name identifier interface to retrieve the set of existing user data, without returning all users. Our implementation of PracticalUserDetailsDAO is PracticalUserDetailsDAOInMemory.

In a real implementation, using a JPA Repository is more appropriate.

Configuration

In the security.xml file, we define our practical user detail service (it will be registered in the authentication manager) and the in-memory DAO bean:
<beans:beans xmlns="http://www.springframework.org/schema/security"
  xmlns:beans="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <http auto-config="true">
    </http>

    <authentication-manager alias="authenticationManager">
        <authentication-provider user-service-ref='practicalUserDetailsServiceInMemory' />
    </authentication-manager>

    <beans:bean id="pud"
        class="com.jverstry.DAO.PracticalUserDetailsDAOInMemory">
    </beans:bean>

</beans:beans>

The JSP Pages

We use two pages. The main page displays registered users (together with a delete link) and registration form:


The second page is displayed when the Create User button is clicked to check the name and the password:


The Controller

The controller is used to check the username and password:
@Controller
public class MyController {

    @Autowired
    private PracticalUserDetailsServiceInMemory pudm;

    @RequestMapping(value = "/")
    public ModelAndView index() {

        ModelAndView result = new ModelAndView("index");

        result.addObject("users", this.pudm.getUsers());

        return result;

    }

    @RequestMapping(value = "/delete/{id}")
    public String delete(@PathVariable(value="id") String id) {

        this.pudm.deleteUser(Long.parseLong(id));

        return "redirect:/";

    }

    @RequestMapping(value = "/create")
    @SuppressWarnings("AssignmentToMethodParameter")
    public ModelAndView add(
            @RequestParam(value="name")
            String name,
            @RequestParam(value="password")
            String password) {

        name = StringUtils.replace(name, " ", "");
        password = StringUtils.replace(password, " ", "");

        String errorMsg = "";

        if ( name.length() == 0 ) {
            errorMsg += "Name is empty ";
        }

        if ( password.length() == 0 ) {
            errorMsg += "Password is empty ";
        }

        if ( errorMsg.isEmpty() ) {
            this.pudm.upsertUser(new PracticalUserDetailsImpl(name, password));
        }

        ModelAndView result = new ModelAndView("create");

        result.addObject("errorMsg", errorMsg);
        result.addObject("username", name);

        return result;

    }

}

Running The Example

One can run it using the maven tomcat:run goal. Then, browse:

  http://localhost:9191/spring-mvc-customized-user/

More Spring related posts here.

Thursday, 27 September 2012

Spring MVC Customized User Login Logout Implementation Example

This post describes how to  implement a customized user access to an Spring MVC web application (login logout). As a prerequisite, readers are advised to read this post which introduces several Spring Security concepts.

The code example is available from Github in the Spring-MVC-Login-Logout directory. It is derived from the Spring MVC with annotations example.

Customized Authentication Provider

In order to implement our own way of accepting user login requests, we need to implement an authentication provider. The following lets users in if their id is identical to their passwords:
public class MyAuthenticationProvider implements AuthenticationProvider {

    private static final List<GrantedAuthority> AUTHORITIES
        = new ArrayList<GrantedAuthority>();

    static {
        AUTHORITIES.add(new SimpleGrantedAuthority("ROLE_USER"));
        AUTHORITIES.add(new SimpleGrantedAuthority("ROLE_ANONYMOUS"));
    }

    @Override
    public Authentication authenticate(Authentication auth)
        throws AuthenticationException {

        if (auth.getName().equals(auth.getCredentials())) {
            return new UsernamePasswordAuthenticationToken(auth.getName(),
                auth.getCredentials(), AUTHORITIES);
        }

        throw new BadCredentialsException("Bad Credentials");

    }

    @Override
    public boolean supports(Class<?> authentication) {
        
        if ( authentication == null ) return false;

        return Authentication.class.isAssignableFrom(authentication);
    }

}

Security.xml

We need to create a security.xml file:
<beans:beans xmlns="http://www.springframework.org/schema/security"
  xmlns:beans="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/security
    http://www.springframework.org/schema/security/spring-security-3.1.xsd">

    <http>
        <intercept-url pattern="/*" access="ROLE_ANONYMOUS"/>
        <form-login
            default-target-url="/"
            always-use-default-target="true" />
        <anonymous />
        <logout />
    </http>

    <authentication-manager alias="authenticationManager">
      <authentication-provider ref="myAuthenticationProvider" />
    </authentication-manager>

    <beans:bean id="myAuthenticationProvider"
      class="com.jverstry.LoginLogout.Authentication.MyAuthenticationProvider" />
    </beans:beans>
The above makes sure all users have the anonymous role to access any page. Once logged in, they are redirected to the main page. If they don't log in, they are automatically considered as anonymous users. A logout function is also declared. Rather than re-implementing the wheel, we use items delivered by Spring itself.

Main Page

We implement a main page displaying the name of the currently logged in user, together with login and logout links:
<%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
<!doctype html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <title>Welcome To MVC Customized Login Logout!!!</title>
</head>
  <body>
    <h1>Spring MVC Customized Login Logout !!!</h1>
    Who is currently logged in? <c:out value="${CurrPrincipal}" /> !<br />
    <a href="<c:url value='/spring_security_login'/>">Login</a>&nbsp;
    <a href="<c:url value='/j_spring_security_logout'/>">Logout</a>
  </body>
</html>

Controller

We need to provide the currently logged in user name to the view:
@Controller
public class MyController {

    @RequestMapping(value = "/")
    public String home(Model model) {

        model.addAttribute("CurrPrincipal",
            SecurityContextHolder.getContext()
                .getAuthentication().getName());

        return "index";

    }

}

Running The Example

Once compiled, one can start the example by browsing: http://localhost:9292/spring-mvc-login-logout/. It will display the following:

Srping Customized Login Logout

Log in using the same id and password:


The application returns to the main and displays:




More Spring related posts here.