Versiones comparadas

Clave

  • Se ha añadido esta línea.
  • Se ha eliminado esta línea.
  • El formato se ha cambiado.

Hasta Julio de 2021 Fundeweb sólo soportaba el login CAS a través de cuenta UM. A partir de esta fecha, CAS soporta login mediante diversos mecanimos (Certificado, Cl@ave, etc.). Para poder soportar desde aplicaciones Fundeweb que CAS utilice diferentes métodos de autenticación y poder reaccionar si alguna de nuestras aplicaciones no soportara algún método indicando los soportados deberemos seguir esta guía.


Para poder aplicar

Nota
titleAplicaciones FundeWeb 1.x

Si estás trabajando con una aplicación FundeWeb 1.x debes leer la guía ...

Pasos a seguir

...

titleRequisitos

...

estos cambios en tu aplicación

...

necesitas FundeWeb IDE 2.0

...

o 2.1

...

.

...


Hay que modificar o añadir las siguientes carpetas y ficheros:

...

AuthenticationManagerBean.java

Añadir esta clase:

  • Asegurar que AuthenticationManagerBean extiende la clase AbstractAuthenticationManagerBean.
  • Añadir los métodos de autenticación validos que ofrece el SSO.


Este es un ejemplo en el que solo admitimos la autenticación mediante correo del SSO para acceder a la aplicación:

Bloque de código
languagejava
themeEclipse
linenumberstrue
package es.um.atica.apiumXXXX.security.authentication;

public class AuthenticationMethodNotSupportedException extends RuntimeException {

	private static final long serialVersionUID = -7140000370097499128L;

	private static final String MENSAJE = "No se soporta el método de autenticación: ";

	public AuthenticationMethodNotSupportedException( String message ) {
		super( MENSAJE + message );
	}

	public AuthenticationMethodNotSupportedException( Throwable cause ) {
		super( MENSAJE, cause );
	}

	public AuthenticationMethodNotSupportedException( String message, Throwable cause ) {
		super( MENSAJE + message, cause );
	}
}

AuthenticationMethodSSO.java

Añadir esta clase que es idéntica a es.um.atica.seam.security.authentication.method.AuthenticationMethodSSO.java salvo porque sobrescribe al final el método preAuthenticate() (línea 96):

Bloque de código
languagejava
themeEclipse
linenumberstrue
package es.um.atica.apium.security.authentication;

import java.nio.charset.StandardCharsets;
import java.util.Map;
import java.util.Objects;

import org.jboss.seam.log.Log;
import org.jboss.seam.log.Logging;
import org.jboss.seam.util.Strings;
import org.umu.atica.servicios.gesper.gente.entity.Persona;
import org.umu.atica.servicios.gesper.gente.exceptions.PersonaException;
import org.umu.atica.servicios.gesper.gente.exceptions.PersonaNotFoundException;

import buscador.servicios.exceptions.ServiceNotFoundException;
import es.um.atica.apium.security.authentication.AuthenticationManagerBean.AuthenticationType;
import es.um.atica.seam.security.authentication.method.AuthenticationMethod;
import es.um.atica.seam.utils.CasClient3Util;

/**
 * Clase para definir el metodo de autenticación por SSO mediante CAS de la UMU.
 * 
 * @author juanmiguelbg
 * @version 0.0.3
 */
public class AuthenticationMethodSSO extends AuthenticationMethod {

	private static final Log LOG = Logging.getLog(AuthenticationMethodSSO.class);

    private static final String CLIENT_NAME_KEY = "clientName";
    private static final String AUTHENTICATION_METHOD_NAME_KEY = "authenticationMethod";
    private static final String CLAVE_CLIENT_NAME = "Cl@ve";
    private static final String CERT_CLIENT_NAME = "Cert";
    private static final String FIRST_NAME_KEY = "FirstName";
    private static final String FAMILY_NAME_KEY = "FamilyName";
    
   /*
     * (non-Javadoc)
     * 
     * @see es.um.atica.util.FundeWebManager#getLog()
     */
    @Override
    protected Log getLog() {
        return LOG;
    }
    
    @Override
	public boolean authenticate() {
		LOG.info("Autenticando a: #0", getCredentials().getUsername());
		getStatusMessages().clearGlobalMessages();
		try {
            if ( isDni( getCredentials().getUsername() ) ) { // Autenticacion Clave - DNI
                loadPersonaByDniCAS( getCredentials().getUsername() );
            } else { // Autenticacion Correo UMU - Ticarum
                loadUser( getCredentials().getUsername() );
            }
			return true;
		} catch (ServiceNotFoundException snfe) {
			LOG.error("Error al buscar el servicio de Gente", snfe);
		} catch (PersonaException pe) {
			LOG.error("Error: al obtener los datos del Usuario en GENTE.", pe);
			processErrorMessage();
		} catch (PersonaNotFoundException pnfe) {
			LOG.error("Error: el usuario no se encuentra en GENTE.", pnfe);
			processErrorMessage();
		} catch ( Throwable t ) {
            LOG.error("Error inesperado.", t);
        }
		return false;
	}

    private void loadPersonaByDniCAS( String username )
            throws PersonaException, PersonaNotFoundException, ServiceNotFoundException {
        try {
            loadPersonaByIdentificador( username );
        } catch ( PersonaNotFoundException pnfe ) {
            LOG.warn( "El usuario no se encuentra en GENTE, completamos con datos del CAS.", pnfe );
            loadPersonaByDniClave( username );
        }
    }

    private void loadPersonaByDniClave( String username ) {
        Map<String, Object> atributos = CasClient3Util.getPrincipalAttributes( CasClient3Util.getCasClient3Principal() );
        LOG.info( "Atributos: #0", atributos );
        String client = (String) atributos.get( CLIENT_NAME_KEY );
        if ( !Strings.isEmpty( client )
                && ( CLAVE_CLIENT_NAME.equals( client ) || CERT_CLIENT_NAME.equals( client ) ) ) {
            String nombre = new String( ( ( String ) atributos.get( FIRST_NAME_KEY ) ).getBytes(), StandardCharsets.UTF_8 );
            String apellidos = new String( ( ( String ) atributos.get( FAMILY_NAME_KEY ) ).getBytes(),
                    StandardCharsets.UTF_8 );
            Persona persona = new Persona( username, nombre, apellidos, null );
            getUmuIdentity().setPersona( persona );
        }
    }
    
    @Override
	public void preAuthenticate() {
		final Map<String, Object> atributos = CasClient3Util.getPrincipalAttributes( CasClient3Util.getCasClient3Principal() );
		final String credentialType = ( String ) atributos.get( AUTHENTICATION_METHOD_NAME_KEY );
		final String client = ( String ) atributos.get( CLIENT_NAME_KEY );

		boolean encontrado = false;
		for ( final AuthenticationType authType : AuthenticationType.values() ) {
			if ( Objects.equals( credentialType, authType.getAuthenticationMethod() )
					&& Objects.equals( client, authType.getClientName() ) ) {
				encontrado = true;
				break;
			}
		}
		if ( !encontrado ) {
			throw new AuthenticationMethodNotSupportedException( client );
		}
	}
}

AuthenticationFactorySSO.java

Añadir esta clase asegurándonos que en el return del método createAuthenticationMethod() ponemos el nombre completo de la clase anterior (línea 11):

Bloque de código
languagejava
themeEclipse
linenumberstrue
package es.um.atica.apium.security.authentication;

import es.um.atica.seam.security.authentication.credentials.CredentialsDefaultUmu;
import es.um.atica.seam.security.authentication.credentials.CredentialsUmu;
import es.um.atica.seam.security.authentication.factories.AuthenticationFactory;
import es.um.atica.seam.security.authentication.method.AuthenticationMethod;

public class AuthenticationFactorySSO implements AuthenticationFactory {

	public AuthenticationMethod createAuthenticationMethod() {
		return new es.um.atica.apium.security.authentication.AuthenticationMethodSSO();
	}

	public CredentialsUmu createCredentials() {
		return new CredentialsDefaultUmu();
	}
}

AuthenticationManagerBean.java

  • Modificar esta clase haciendo que extienda a AbstractAuthenticationManagerBean en lugar de a FundeWebManagerBean (línea 37).
  • Modificar el enumerado AuthenticationType (línea 54) y añadir el método get getAuthenticationTypes (línea 89).
  • Modificar los métodos getFactoria (línea 148) y getAuthenticationTypeLabel (línea 165) y nos asegurarnos que el return del método getFactoria() en el caso SSO ponemos el nombre completo de la clase anterior (línea 157).
Bloque de código
languagejava
themeEclipse
linenumberstrue
package es.um.atica.apium.security.authentication;

import static org.jboss.seam.ScopeType.SESSION;
import static org.jboss.seam.annotations.Install.FRAMEWORK;

import java.io.Serializable;
import java.util.MissingResourceException;
import java.util.ResourceBundle;

import javax.faces.model.SelectItem;

import org.jboss.seam.Component;
import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Observer;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Startup;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.contexts.Contexts;
import org.jboss.seam.core.SeamResourceBundle;
import org.jboss.seam.log.Log;
import org.jboss.seam.log.Logging;

import es.um.atica.apium.security.authentication.ws.AuthenticationFactoryCorreo;
import es.um.atica.seam.security.CredentialsAdapter;
import es.um.atica.seam.security.UmuIdentity;
import es.um.atica.seam.security.authentication.AbstractAuthenticationManagerBean;
import es.um.atica.seam.security.authentication.credentials.CredentialsUmu;
import es.um.atica.seam.security.authentication.factories.AuthenticationFactory;
import es.um.atica.seam.security.authentication.method.AuthenticationMethod;

@Name( "authenticationManagerBean" )
@Scope( SESSION )
@Install( precedence = FRAMEWORK )
@BypassInterceptors
@Startup
public class AuthenticationManagerBean extends AbstractAuthenticationManagerBean implements Serializable {

	/**
	 * serialVersionUID generado automaticamente
	 */
	private static final long serialVersionUID = -6064182119922723132L;

	/** Logger de la clase */
	private static final Log LOG = Logging.getLog( AuthenticationManagerBean.class );

	protected SelectItem[] selectItemsAutentication;

	/** Credencial actual */
	protected CredentialsAdapter credentialsAdapter;

	protected AuthenticationType authenticationType;

	public enum AuthenticationType {
		CORREO( null, null, "label.tipo_acceso_correo" ),
		SSO( "LdapAuthenticationHandler", null, "label.authentication.type.correoum" ),
		SSO_CLAVE( "ClientAuthenticationHandler", "Cl@ve", "label.authentication.type.clave" ),
		// SSO_CMN( "ClientAuthenticationHandler", "CMN", "label.authentication.type.cmn" ),
		SSO_CERT( "ClientAuthenticationHandler", "Cert", "label.authentication.type.cert" );

		private String authenticationMethod;
		private String clientName;
		private String descKey;

		AuthenticationType( String authenticationMethod, String clientName ) {
			this.authenticationMethod = authenticationMethod;
			this.clientName = clientName;
		}

		AuthenticationType( String authenticationMethod, String clientName, String descKey ) {
			this( authenticationMethod, clientName );
			this.descKey = descKey;
		}

		public String getAuthenticationMethod() {
			return authenticationMethod;
		}

		public String getClientName() {
			return clientName;
		}

		public String getDescKey() {
			return descKey;
		}

	}

	public AuthenticationType[] getAuthenticationTypes() {
		return AuthenticationType.values();
	}

	private static final String ERROR_FIRMA = "0";

	public AuthenticationManagerBean() { // Por defecto CORREO
		this.credentialsAdapter = ( CredentialsAdapter ) this.getCredentials();
		this.authenticationType = AuthenticationType.CORREO;
		this.activateCredentialsUmu();
		int idx = 0;
		selectItemsAutentication = new SelectItem[AuthenticationType.values().length];
		for ( AuthenticationType type : AuthenticationType.values() ) {
			selectItemsAutentication[idx++] = new SelectItem( type.name(), getAuthenticationTypeLabel( type ) );
		}
	}

	public void activateCredentialsUmu() {
		LOG.info( "Entrar en activateCredentialsUmu: #0", this.authenticationType.name() );
		this.credentialsAdapter.setCredentialsUmu( getFactoria( this.authenticationType ).createCredentials() );
	}

	/**
	 * Metodo para activar una credencial.<br />
	 * Si la que se desea activar, es la que est� actualmente, no se hace nada y se devuelve false. En otro caso se
	 * devolver� true.
	 * 
	 * @param credencial
	 *                   Clase de Credencial a activar.
	 * @return Si => se creo una nueva credencial. No => ya estaba esa misma credencial activa.
	 */
	public boolean activateCredentialsUmu( AuthenticationType authenticationType ) {
		LOG.info( "Entrar en activateCredentialsUmu: #0",
				( authenticationType != null ? authenticationType.name() : "" ) );
		if ( ( this.getCredentialsUmu() != null ) && ( this.authenticationType == authenticationType ) ) {
			if ( LOG.isDebugEnabled() ) {
				LOG.debug( "La credencial actual y la pedida son iguales, luego no se crear� una nueva: #0.",
						this.authenticationType );
			}
			return false;
		}
		if ( authenticationType != null ) {
			this.setAuthenticationType( authenticationType );
		} else { // Por defecto CORREO
			this.setAuthenticationType( AuthenticationType.CORREO );
		}
		this.credentialsAdapter.setCredentialsUmu( getFactoria( this.authenticationType ).createCredentials() );
		return true;
	}

	public AuthenticationMethod getAuthenticationMethod() {
		return this.getFactoria( this.authenticationType ).createAuthenticationMethod();
	}

	/**
	 * @param authenticationType
	 *                           - parametro de Seam por defecto
	 * @return
	 */
	protected AuthenticationFactory getFactoria( AuthenticationType authenticationType ) {
		if ( this.authenticationType == null ) {
			activateCredentialsUmu( AuthenticationType.CORREO );
		}
		switch ( this.authenticationType ) {
			case SSO: // case SSO
			case SSO_CLAVE:
			//case SSO_CMN:
			case SSO_CERT:
				return new es.um.atica.apium.security.authentication.AuthenticationFactorySSO();
			case CORREO: // case CORREO
				return new AuthenticationFactoryCorreo();
			default:
				return new es.um.atica.apium.security.authentication.AuthenticationFactoryRadius();
		}
	}

	protected String getAuthenticationTypeLabel( AuthenticationType authenticationType ) {
		ResourceBundle srb = SeamResourceBundle.getBundle();

		try {
			return srb.getString( authenticationType.getDescKey() );
		} catch ( MissingResourceException mre ) {
			LOG.error( "Error al obtener las etiquetas para los tipos de autenticacion.", mre );
		}
		return "";
	}

	/**
	 * Obtiene la credencial actual.
	 */
	public CredentialsUmu getCredentialsUmu() {
		return this.credentialsAdapter.getCredentialsUmu();
	}

	public AuthenticationType getAuthenticationType() {
		return authenticationType;
	}

	public void setAuthenticationType( AuthenticationType authenticationType ) {
		LOG.debug( "Entra en setAuthenticationType: #0 - #1", authenticationType.hashCode(),
				authenticationType.name() );
		this.authenticationType = authenticationType;
	}

	public boolean isCorreoAuthentication() {
		return this.authenticationType == AuthenticationType.CORREO;
	}

	public boolean isSsoAuthentication() {
		return this.authenticationType == AuthenticationType.SSO;
	}

	public SelectItem[] getSelectItemsAutentication() {
		return selectItemsAutentication;
	}

	@Observer( UmuIdentity.EVENT_AUTHENTICATING_BY_CAS )
	public void activarAuthenticacionSSO() {
		LOG.debug( "Entra en activarAuthenticacionSSO" );
		this.authenticationType = AuthenticationType.SSO;
		this.activateCredentialsUmu();
	}

	/*
	 * (non-Javadoc)
	 * @see es.um.atica.util.FundeWebManager#getLog()
	 */
	@Override
	protected Log getLog() {
		return LOG;
	}

	public static AuthenticationManagerBean instance() {
		if ( !Contexts.isSessionContextActive() ) {
			throw new IllegalStateException( "no session context active" );
		}
		return ( AuthenticationManagerBean ) Component.getInstance( AuthenticationManagerBean.class );
	}

	public static String getErrorfirma() {
		return ERROR_FIRMA;
	}
}

AuthenticatorAction.java

Sustituir la clase completa:

Bloque de código
languagejava
themeEclipse
linenumberstrue
package es.um.atica.apium.security.authentication;

import static org.jboss.seam.annotations.Install.FRAMEWORK;

import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.log.Log;
import org.jboss.seam.log.Logging;

import es.um.atica.seam.security.authentication.AbstractAuthenticationManagerBean;
import es.um.atica.seam.security.authentication.AbstractAuthenticatorAction;

@Name( "authenticator" )
@Install( precedence = FRAMEWORK )
@BypassInterceptors
public class AuthenticatorAction extends AbstractAuthenticatorAction {

	private static final Log LOG = Logging.getLog( AuthenticatorAction.class );

	@Override
	protected AbstractAuthenticationManagerBean getAuthenticationManagerBean() {
		return AuthenticationManagerBean.instance();
	}

	/*
	 * (non-Javadoc)
	 * @see es.um.atica.util.FundeWebManagerBean#getLog()
	 */
	@Override
	protected Log getLog() {
		return LOG;
	}
}

messages_en.properties

Añadir al final del fichero las siguientes variables.

Bloque de código
themeEclipse
linenumberstrue
#------------- Páginas de error ------------
page.error.authmethod.title=Authentication method not supported
page.error.authmethod.desc=The authentication method used is not allowed for this application, The allowed methods:
page.error.authmethod.link.pre=To access the application, you must
page.error.authmethod.link=change the authentication method
page.error.authmethod.link.post=to one of those allowed.

page.error.noauth.title=You're not authorized
page.error.noauth.desc=Sorry, you are not authorized to perform this action.
page.error.noauth.link.pre=If you consider that you should have access, contact
page.error.noauth.link=the User Service Center
page.error.noauth.link.post=.

messages_es.properties

Añadir al final del fichero las siguientes variables.

Bloque de código
themeEclipse
linenumberstrue
#------------- Páginas de error ------------
page.error.authmethod.title=M\u00E9todo de autenticaci\u00F3n no soportado
page.error.authmethod.desc=El m\u00E9todo de autenticaci\u00F3n utilizado no es v\u00E1lido para esta aplicaci\u00F3n, solamente se permiten los m\u00E9todos:
page.error.authmethod.link.pre=Para acceder a la aplicaci\u00F3n debe
page.error.authmethod.link=cambiar de m\u00E9todo de autenticaci\u00F3n
page.error.authmethod.link.post=a uno de los permitidos.

page.error.noauth.title=Usted no est\u00E1 autorizado
page.error.noauth.desc=Lo siento, usted no est\u00E1 autorizado a realizar esta acci\u00F3n.
page.error.noauth.link.pre=Si considera que deber\u00EDa tener acceso, contacte con 
page.error.noauth.link=el Centro de Atenci\u00F3n a Usuarios
page.error.noauth.link.post=.

pages.xml

Añadir la siguiente regla de navegación:

Bloque de código
themeEclipse
linenumberstrue
<navigation from-action="#{identity.relogByCAS}">
	<redirect url="https://${cas.server.url}.um.es/cas/logout?service=https://${cas.application.url}/#{request.contextPath}" />
</navigation>

Añadir la siguiente excepción:

Bloque de código
themeEclipse
linenumberstrue
<exception class="es.um.atica.apium.security.authentication.AuthenticationMethodNotSupportedException">
	<redirect view-id="/error_auth_method.xhtml">
		<message severity="error">#{messages['es.um.atica.security.authentication.AuthenticationMethodNotSupportedException']}</message>
	</redirect>
</exception>

Modificar la excepción para la clase org.jboss.seam.security.AuthorizationException:

Bloque de código
themeEclipse
linenumberstrue
<exception class="org.jboss.seam.security.AuthorizationException">
	<redirect view-id="/error_no_auth.xhtml">
		<message severity="error">#{messages['org.jboss.seam.security.AuthorizationException']}</message>
	</redirect>
</exception>

ApiumIdentity.java

Modificar esta clase para añadir el método relogByCAS:

Bloque de código
languagejava
themeEclipse
linenumberstrue
package es.um.atica.apium.security.authentication;

import org.jboss.seam.ScopeType;
import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.Scope;
import org.jboss.seam.annotations.Startup;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.core.Events;
import org.jboss.seam.log.Log;
import org.jboss.seam.log.Logging;
import org.jboss.seam.web.Session;

import es.um.atica.seam.security.UmuIdentity;

@Name( "org.jboss.seam.security.identity" )
@Scope( ScopeType.SESSION )
@Install( precedence = Install.APPLICATION, classDependencies = "org.umu.atica.servicios.gesper.gente.entity.Persona" )
@BypassInterceptors
@Startup
public class ApiumIdentity extends UmuIdentity {

	private static final long serialVersionUID = 4315185968632267803L;
	private static final Log LOG = Logging.getLog( UmuIdentity.class );

	public static final String ROL_ADMINISTRADOR = "ADMIN";

	public boolean esUsuarioUmu() {
		return ( this.getPersona().getCorreo().endsWith( "@um.es" )
				|| this.getPersona().getCorreo().endsWith( "@ticarum.es" ) );
	}

	public static String getRolAdministrador() {
		return ROL_ADMINISTRADOR;
	}

	public void relogByCAS() {
		LOG.debug( "relogByCAS: #0", getCredentials().getUsername() );
		unAuthenticate();
		Session.instance().invalidate();
		if ( Events.exists() ) {
			Events.instance().raiseEvent( EVENT_LOGGED_OUT );
		}
	}
}

error_template.xhtml

Añadir template para páginas de error:

Bloque de código
languagexml
themeEclipse
linenumberstrue
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html version="-//W3C//DTD XHTML 1.1//EN" 
	lang="#{locale.language}" xmlns="http://www.w3.org/1999/xhtml"
	xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:s="http://jboss.org/schema/seam/taglib"
	xmlns:p="http://primefaces.org/ui"
	xmlns:fdw="http://www.um.es/atica/fundeweb"
	xsi:schemaLocation="http://www.w3.org/1999/xhtml
                          http://www.w3.org/MarkUp/SCHEMA/xhtml11.xsd">
<h:head>
	<f:facet name="first">
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
		<meta http-equiv="X-UA-Compatible" content="IE=edge" />
		<meta name="viewport" content="width=device-width, initial-scale=1" />
		<title><h:outputText value="#{messages['application.title']}" /></title>
		<!--  -->
		<link rel="shortcut icon" href="#{request.contextPath}/resources/img/icon.png" />
		<ui:insert name="head-first" />
	</f:facet>
	<f:facet name="last">
		<fdw:outputStylesheet library="fundeweb" name="primeflex/2_0/primeflex.min.css" />
		<!-- Personalizacion UMU -->
		<fdw:outputStylesheet library="themes" name="um/1_1/css/font.css" />
		<fdw:outputStylesheet library="themes" name="um/1_1/css/layoutUMU.css" />
		<fdw:outputStylesheet library="themes" name="um/1_1/css/estiloUMU.css" />

		<!-- Personalizacion de la aplicacion -->
		<fdw:outputStylesheet library="css" name="custom.css" />
	</f:facet>
</h:head>
<h:body>
	<f:view>
		<div id="main-wrapper" class="error-page">
			<header class="topbar">
				<nav class="navbar">
					<span class="app-name d-sm-none" style="margin-left: 73px;"> #{messages['application.name']} </span>
					<span class="app-name d-md-none"> #{messages['application.name']} </span>
				</nav>
			</header>
			<div class="page-wrapper">
				<div class="main-content" style="margin: 0;">
					<main class="page-content ui-g">
						<div class="ui-g-0 ui-lg-2"></div>
						<div class="ui-g-12 ui-lg-8">
							<ui:insert name="body" />
						</div>
					</main>
					<footer class="footerRow clearfix">
						<span>#{messages['application.foot.universidad']} — #{messages['application.foot.atica']}</span>

						<s:fragment rendered="#{init.debug}">
							<ui:include src="/layout/pie_debug.xhtml" />
						</s:fragment>
					</footer>
				</div>
			</div>
		</div>
	</f:view>
</h:body>
</html>

error_auth_method.xhtml

Añadir página de error en el método de autorización.

Bloque de código
languagexml
themeEclipse
linenumberstrue
<ui:composition template="error_template.xhtml"
	xmlns="http://www.w3.org/1999/xhtml"
	xmlns:ui="http://java.sun.com/jsf/facelets"
	xmlns:f="http://java.sun.com/jsf/core"
	xmlns:h="http://java.sun.com/jsf/html"
	xmlns:s="http://jboss.org/schema/seam/taglib"
	xmlns:p="http://primefaces.org/ui"
	xmlns:c="http://java.sun.com/jsp/jstl/core">

	<ui:define name="body">
		<h1 class="titulo-pagina">#{messages['page.error.authmethod.title']}</h1>
		<p class="text-size-big-4 font-weight-medium p-mt-5">
			#{messages['page.error.authmethod.desc']}
		</p>
		<ul>
			<c:forEach var="_authType" items="#{authenticationManagerBean.authenticationTypes}">
				<c:if test="#{not empty _authType.descKey}">
					<li>#{messages[_authType.descKey]}</li>
				</c:if>
			</c:forEach>
		</ul>

		<h:form>
			<p class="text-size-big-4 font-weight-medium p-mt-5" style="margin">
				#{messages['page.error.authmethod.link.pre']}
				<s:link action="#{identity.relogByCAS}" propagation="none"
						includePageParams="false" value="#{messages['page.error.authmethod.link']}" />
				#{messages['page.error.authmethod.link.post']}
			</p>
		</h:form>
	</ui:define>
</ui:composition>

error_no_auth.xhtml

Añadir página de error no autorizado.

...

languagexml
themeEclipse
linenumberstrue

...

...

import org.jboss.seam.annotations.Factory;

import es.um.atica.seam.security.authentication.Constants;
import es.um.atica.seam.security.authentication.method.SSOAuthenticationMethods;


@Name( "authenticationManagerBean" )
@Scope( SESSION )
@Install( precedence = FRAMEWORK )
@BypassInterceptors
@Startup
public class AuthenticationManagerBean extends AbstractAuthenticationManagerBean {

	// Declaracion de los metodos de autenticacion validos por SSO
	private static final SSOAuthenticationMethods[] VALIDS_SSO_AUTHENTICATION_METHODS = {
		SSOAuthenticationMethods.SSO_CORREO
	};

	...

    // Forma de hacer accesible los metodos de autenticacion validos por SSO
	@Factory( Constants.SSO_AUTHENTICATION_METHODS_COMPONENT_NAME )
	public SSOAuthenticationMethods[] getValidsSSOAuthenticationMethods() {
		return VALIDS_SSO_AUTHENTICATION_METHODS;
	}
}


Los métodos de autenticación posibles son:


Bloque de código
SOAuthenticationMethods[]: SSO_CORREO, SSO_MFA_CORREO_OTP, SSO_CLAVE, SSO_CLAVE_CERT, SSO_CLAVE_EIDAS, SSO_CLAVE_SEGSOC, SSO_CLAVE_PIN24H, SSO_CLAVE_PIN24H_MOVIL, SSO_CMN


Añadir SSO_CORREO implica, que se aceptan SSO_CORREO y SSO_MFA_CORREO_OTP.

Añadir SSO_CLAVE implica, que se aceptan todos los métodos de Cl@ve: SSO_CLAVE_CERT, SSO_CLAVE_EIDAS, SSO_CLAVE_SEGSOC, SSO_CLAVE_PIN24H y SSO_CLAVE_PIN24H_MOVIL.


Sino se usa la anotación @Factory, podemos declarar la factoría en el fichero components.xml:

Bloque de código
<factory name="es.um.atica.security.authentication.ssoAuthenticationMethods" value="#{authenticationManagerBean.validsSSOAuthenticationMethods}"/>

o

Bloque de código
<factory name="es.um.atica.security.authentication.ssoAuthenticationMethods" method="#{authenticationManagerBean.getValidsSSOAuthenticationMethods}"/>


AuthenticatorAction.java

  • Asegurar que AuthenticatorAction extiende la clase AbstractAuthenticatorAction.

La clase normalmente, suele parecerse al siguiente ejemplo:

Bloque de código
languagejava
themeEclipse
linenumberstrue
package es.um.atica.XXXX.security.authentication;

import static org.jboss.seam.annotations.Install.FRAMEWORK;

import org.jboss.seam.annotations.Install;
import org.jboss.seam.annotations.Name;
import org.jboss.seam.annotations.intercept.BypassInterceptors;
import org.jboss.seam.log.Log;
import org.jboss.seam.log.Logging;

import es.um.atica.seam.security.authentication.AbstractAuthenticationManagerBean;
import es.um.atica.seam.security.authentication.AbstractAuthenticatorAction;

@Name( "authenticator" )
@Install( precedence = FRAMEWORK )
@BypassInterceptors
public class AuthenticatorAction extends AbstractAuthenticatorAction {

	private static final Log LOG = Logging.getLog( AuthenticatorAction.class );

	@Override
	protected AbstractAuthenticationManagerBean getAuthenticationManagerBean() {
		return AuthenticationManagerBean.instance();
	}

	/*
	 * (non-Javadoc)
	 * @see es.um.atica.util.FundeWebManagerBean#getLog()
	 */
	@Override
	protected Log getLog() {
		return LOG;
	}
}


pages.xml

Añadir la siguiente regla de navegación al final de la declaración de <page view-id="*">:

Bloque de código
themeEclipse
linenumberstrue
<navigation from-action="#{identity.relogByCAS}">
    <redirect url="https://${cas.server.url}.um.es/cas/logout">
    	<param name="service" value="https://${cas.application.url}#{request.contextPath}"/>
    </redirect>
</navigation>


Añadir la siguiente excepción:

Bloque de código
themeEclipse
linenumberstrue
    <exception class="es.um.atica.seam.security.authentication.exceptions.AuthenticationMethodNotSupportedException">
	    <redirect view-id="/fundeweb/error_auth_method.xhtml">
	        <message severity="error">#{messages['es.um.atica.security.authentication.AuthenticationMethodNotSupportedException']}</message>
	    </redirect>
	</exception>


Modificar la excepción para la clase org.jboss.seam.security.AuthorizationException:

Bloque de código
themeEclipse
linenumberstrue
	<exception class="org.jboss.seam.security.AuthorizationException">
		<redirect view-id="/fundeweb/error_no_auth.xhtml">
			<message severity="error">#{messages['org.jboss.seam.security.AuthorizationException']}</message>
		</redirect>
	</exception>



Comprobación


Es necesaria realizar la comprobación de la existencia del fichero recomendaciones.xhtml que se tiene que encontrar en la carpeta src/main/webapp/layout del módulo WEB. Sino existe la podéis descargar de recomendaciones.xhtml