Autenticación AS400 usando Spring Security

En algunos Bancos que aun siguen le gusta que sus aplicaciones se autentiquen  contra su  AS400 para así controlar los accesos a los recursos directamente desde este, hoy los quiero mostrar como crear una aplicación Java usando Spring con Spring Security para hacer este simple Login.

Herramientas Utilizadas en el Ejemplo:

  1. Maven
  2. Tomcat 8
  3. Java 8
  4. Netbeans 8

Ahora si comenzamos, voy a explicar los archivos más importantes, si quieres el código completo lo puedes descargar desde mi Github

El archivo pom.xml

En este archivo coloque todas las dependencias necesarias para usar Spring y Spring Security solo quiero destacar que para usar el api de AS400 coloque la dependencia de esta forma ya que no existe en el repositorio de Maven:

<dependency>
    <groupId>com.ibm</groupId>
    <artifactId>jt400</artifactId>
    <version>6.1.0.6</version>
    <scope>system</scope>
    <systemPath>${basedir}/lib/jt400.jar</systemPath>
</dependency>

Archivo web.xml

Aquí he configurado el Servlet de Spring y Filtro de Spring Security

    <servlet>
        <servlet-name>mvc-dispatcher</servlet-name>
        <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
        <init-param>
            <param-name>contextConfigLocation</param-name>
            <param-value>/WEB-INF/applicationContext.xml</param-value>
        </init-param>
        <load-on-startup>1</load-on-startup>
    </servlet>
    <servlet-mapping>
        <servlet-name>mvc-dispatcher</servlet-name>
        <url-pattern>/app/*</url-pattern>
    </servlet-mapping>
    <filter>
        <filter-name>springSecurityFilterChain</filter-name>
        <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
    </filter>
    <filter-mapping>
        <filter-name>springSecurityFilterChain</filter-name>
        <url-pattern>/*</url-pattern>
    </filter-mapping>

Archivo spring-security.xml

En la configuración se SpringSecurity cree el authenticationProvider el cual usaremos para validar la sesión desde el AS400

    <beans:bean id="authenticationProvider"
         class="com.stricore.as400.security.CustomAuthenticationProvider">
            <beans:property name="nonceValiditySeconds" value="10"/>
            <beans:property name="key" value="KEY"/>
    </beans:bean>
     
    <security:authentication-manager alias="authenticationManager">
        <security:authentication-provider ref="authenticationProvider"/>
    </security:authentication-manager>

Archivo login.jsp

Vamos a crear nuestro archivo login.jsp el mismo la vamos a colocar dentro de WEB-INF/pages/auth/login.jsp, para los que no tienen experiencia con Spring Security

<form method="POST" id="form1" name="form1" 
    action="${pageContext.servletContext.contextPath }/j_spring_security_check"
    autocomplete="off">
    <input type="hidden" name="${_csrf.parameterName}" value="${_csrf.token}"/>
    <input type="hidden" name="timeout" id="timeout" value="${timeout}" />
    <c:out value="${message}"/>
    <c:if test="${sessionScope.levelerror != null}">
      <div id="levelerror " class="error">
      <c:out value="${sessionScope.levelerror}" />
      <c:remove var="levelerror" scope="session"/>
      </div>    
    </c:if>
    <table cellspacing="1">
      <tr>
         <td>
            <label for="signin_username">Usuario</label>
         </td>
      </tr>
      <tr>
         <td>
            <input id="j_username" name="j_username" type="text" value="" maxlength="10"  type="text">
         </td>
      </tr>
      <tr>
         <td>
            <label for="signin_password">Contraseña</label>
         </td>
      </tr>
      <tr>
         <td>
           <input id="j_password" name="j_password" type="password" value="" maxlength="10">
          </td>
       </tr>
       <tr>
          <td>
             <input type="submit" value="Autenticar">
          </td>
       </tr>
     </table>
   </form>

Clase AuthController.java

Este es el controlado que va a presentar la pantalla de inicio de sesión:

@Controller
@RequestMapping("/auth")
public class AuthController {

    @Autowired
    CustomAuthenticationProvider authenticationProvider;

    @RequestMapping(value = "/login", method = RequestMethod.GET)
    public String getLoginPage(ModelMap model, HttpServletRequest request, HttpSession session) {
        String timeout = authenticationProvider.calculateNonce();
        session.setAttribute("timeout", timeout);
        model.addAttribute("timeout", timeout);

        try {
            if (request.getParameter("message") != null) {
                String message = "";
                long error = Long.parseLong(request.getParameter("message"));
                if (error == 1) {
                    message = "Usuario o contraseña no válidos!";
                } else if (error == 2) {
                    message = "Sesión cerrada con éxito";
                } else if (error == 3) {
                    message = "Su sesión expiro!";
                } else if (error == 4) {
                    message = "Su sesión expiro!";
                } else if (error == 5) {
                    message = "Su sesión se ha cerrado por que ha sido abierta desde otro sitio!";
                }
                request.getSession().setAttribute("levelerror", message);
            }
        } catch (Exception e) {
        }
        return "/auth/login";
    }

    @RequestMapping(value = "/logout", method = RequestMethod.GET)
    public String getLogoutPage(ModelMap model, HttpServletRequest request, HttpSession session) {
        session.removeAttribute("username");
        session.invalidate();

        return "/auth/logout";
    }

    @RequestMapping(value = "/denied", method = RequestMethod.GET)
    public String getDeniedPage(@RequestParam(value = "error", required = false) boolean error,
            ModelMap model) {

        return "/auth/denied";
    }

}

Clase CustomAuthenticationProvider.java

En esta clase vamos a iniciar la sesión el AS400, dentro de ella podemos encotrar tres metodos:

authenticate:

    @Override
    public final Authentication authenticate(Authentication authentication) {
        final UsernamePasswordWithTimeoutAuthenticationToken authenticationToken = (UsernamePasswordWithTimeoutAuthenticationToken) authentication;
        validateTimeout(authenticationToken);

        String name = authentication.getName();
        String password = authentication.getCredentials().toString();

        if (isPasswordCorrect(authentication)) {
            List<GrantedAuthority> grantedAuths = new ArrayList<GrantedAuthority>();
            grantedAuths.add(new SimpleGrantedAuthority("ROLE_USER"));
            grantedAuths.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
            grantedAuths.add(new SimpleGrantedAuthority("superuser"));
            Authentication auth = new UsernamePasswordAuthenticationToken(name, password, grantedAuths);
            return auth;
        } else {
            return null;
        }
    }

isPasswordCorrect: Aquí vamos a iniciar la sesión contra el AS400 con el método validateSignon del jt400.

    protected boolean isPasswordCorrect(Authentication authentication) {        
        String systemName = "PUB1.RZKH.DE";
        String userName = authentication.getName();
        String userPwd = authentication.getCredentials().toString();
        AS400 myAS400 = new AS400(systemName);
        String msg = "authentification failed on " + systemName + " for user" + userName;
        try {
            myAS400.validateSignon(userName, userPwd);
        } catch (AS400SecurityException e) {
            translateSecurityExceptionAndRethrow(e, userName, systemName);
            throw new BadCredentialsException(msg, e);
        } catch (IOException e) {
            throw new AuthenticationServiceException(msg, e);
        }
        return true;
    }

translateSecurityExceptionAndRethrow: Como el método validateSignon no retorna nada si es correcto, el lanza una excepción de error de autenticación el cual vamos a manjar con este otro método:

    private void translateSecurityExceptionAndRethrow(AS400SecurityException e,
            String userName, String systemName) {
        int code = e.getReturnCode();
        String msg = "authentification failed on " + systemName + " for user" + userName;
        if (code == AS400SecurityException.PASSWORD_INCORRECT) {
            throw new BadCredentialsException(msg, e);
        } else if (code == AS400SecurityException.USERID_UNKNOWN) {
            throw new UsernameNotFoundException(msg, e);
        } else if (code == AS400SecurityException.PASSWORD_EXPIRED) {
            throw new CredentialsExpiredException(msg, e);
        } else if (code == AS400SecurityException.PASSWORD_INCORRECT_USERID_DISABLE) {
            throw new CredentialsExpiredException(msg, e);
        } else if (code == AS400SecurityException.USERID_DISABLE) {
            throw new CredentialsExpiredException(msg, e);
        } else {
            throw new BadCredentialsException(msg, e);
        }
    }

 

Ahora vamos a correr el proyecto desde Netbeans usando Tomcat:

Captura de pantalla de 2015-09-25 11:52:30

Y ahora entramos al inicio de sesion:

Captura de pantalla de 2015-09-25 11:52:24

Descargar el código desde Github también puedes seguirme para que recibas información de todas las soluciones Java con AS400 que voy a seguir montando.

Comments are closed.