Prerequisiti
JDK 8, apache tomcat 8 per installazione del cas-server
JDK 7, per il runtime di liferay 6.2
Configurazione del cas server
Come prima cosa scarichiamo i sorgenti del cas-server
https://github.com/apereo/cas/releases/tag/v5.0.4
Scompattiamo i sorgenti e portiamoci nella cartella cas-server-webapp
cas5.0.4/webapp/cas-server-webapp
Modifichiamo il build.gradle
per aggiungere il supporto al connettore JDBC (che di default non è installato) che permetterà al CAS di accedere allo stesso database di Liferay
compile project(":support:cas-server-support-jdbc")
Purtroppo CAS e Liferay utilizzano due diversi sistemi di encrypting della password.
Dopo vari tentativi sono riuscito a modificare i sorgenti del CAS per permettere il corretto encrypt della password da parte del CAS server.
Per prima cosa ho aggiunto le seguenti properties nel file application.properties
cas.authn.jdbc.query[0].sql=SELECT password_ FROM USER_ WHERE emailaddress=?
cas.authn.jdbc.query[0].url=<connection_url>
cas.authn.jdbc.query[0].dialect=org.hibernate.dialect.PostgreSQL94Dialect
cas.authn.jdbc.query[0].user=<user>
cas.authn.jdbc.query[0].password=<password>
cas.authn.jdbc.query[0].driverClass=org.postgresql.Driver
cas.authn.jdbc.query[0].healthQuery=SELECT 1
cas.authn.jdbc.query[0].passwordEncoder.characterEncoding=UTF-8
cas.authn.jdbc.query[0].passwordEncoder.encodingAlgorithm=SHA1
cas.authn.jdbc.query[0].passwordEncoder.type=PBKDF2
Ho configurato come encoder il PDKDF2 che non è supportato da CAS ma è utilizzato di default da Liferay
Per far si che che IL CAS supporti questo encoder (secondo le logiche di liferay) ho dovuto modificare un paio di classi e creare alcune classi accessorie.
La classi che ho modificato sono
org.apereo.cas.configuration.model.core.authentication.PasswordEncoderProperties
org.apereo.cas.configuration.support.Beans
Nella prima ho aggiunto il support al nuovo encoder, mentre sulla seconda ho gestito il parametro per istanziare un nuovo encoder type.
public static PasswordEncoder newPasswordEncoder(final PasswordEncoderProperties properties) {
switch (properties.getType()) {
case NONE:
return NoOpPasswordEncoder.getInstance();
case DEFAULT:
return new DefaultPasswordEncoder(properties.getEncodingAlgorithm(), properties.getCharacterEncoding());
case STANDARD:
return new StandardPasswordEncoder(properties.getSecret());
case PBKDF2:
LOGGER.info("Creating PBKDF2 encoder");
return new PBKDF2PasswordEncoder(properties.getSecret(), properties.getCharacterEncoding());
default:
LOGGER.debug("Creating BCRYPT password encoder given the strength [{}] and secret in the configuration",
properties.getStrength());
if (StringUtils.isBlank(properties.getSecret())) {
LOGGER.debug("Creating BCRYPT encoder without secret");
return new BCryptPasswordEncoder(properties.getStrength());
}
LOGGER.debug("Creating BCRYPT encoder with secret");
return new BCryptPasswordEncoder(properties.getStrength(),
new SecureRandom(properties.getSecret().getBytes(StandardCharsets.UTF_8)));
}
}
Fatto questo ho implementato un nuovo encoder prendendo spunto da uno esistente. (Per ottenere i sorgenti contattateci!)
Dalla root-folder di cas lanciamo il seguente comando
gradlew war
Non abbiamo bisogno di installare gradle in quanto CAS contiene il gradle wrapper
.
Rinominiamo il war appena generato in cas-server.war
(eliminando quindi la versione)
A questo punto dobbiamo generare il certificato e importarlo nelle jre di entrambe le jdk
keytool -genkey -alias tomcat -keypass changeit -keyalg RSA
Enter keystore password: changeit
What is your first and last name?
[Unknown]: localhost
What is the name of your organizational unit?
[Unknown]:
What is the name of your organization?
[Unknown]:
What is the name of your City or Locality?
[Unknown]:
What is the name of your State or Province?
[Unknown]:
What is the two-letter country code for this unit?
[Unknown]:
Is CN=localhost, OU=Unknown, O=Unknown, L=Unknown, ST=Unknown, C=Unknown correct?
[no]: y
Esportare il certificato in un file che, per esempio, possiamo chiamare: server.cert
keytool -export -alias tomcat -keypass changeit -file server.cert
Importarlo nella jre di entrambe le jdk
keytool -import -alias tomcat -file server.cert -keypass changeit -keystore %JAVA_HOME%/jre/lib/security/cacerts
Dopo aver importato i certificati dobbiamo abilitare il connettore https su entrambi i tomcat
Editiamo il server.xml del cas-server e aggiungiamo
<Connector port="9443" maxHttpHeaderSize="8192" protocol="org.apache.coyote.http11.Http11NioProtocol"
maxThreads="150" minSpareThreads="25" maxSpareThreads="75"
enableLookups="false" disableUploadTimeout="true"
acceptCount="100" scheme="https" secure="true"
clientAuth="false" sslProtocol="TLS" SSLEnabled="true" keystoreFile="${user.home}/.keystore" keystorePass="changeit"/>
Ora editiamo in maniera speculare il server.xml del tomcat di liferay
<Connector SSLEnabled="true" acceptCount="100" clientAuth="false" disableUploadTimeout="true" enableLookups="false"
keystoreFile="${user.home}/.keystore" keystorePass="changeit"
maxHttpHeaderSize="8192" maxSpareThreads="75" maxThreads="150" minSpareThreads="25" port="8443"
protocol="org.apache.coyote.http11.Http11Protocol" scheme="https" secure="true" sslProtocol="TLS"/>
Ora possiamo startare il server liferay.
Ora andiamo nel pannello di controllo e nella sezione riguardante il cas configuriamo i paramentri nel modo seguente
Abilitiamo il flag
configuriamo gli altri parametri in questo modo
- cas login: https://localhost:9443/cas-server/login
- cas logout:https://localhost:9443/cas-server/logout
- server name:https://localhost:8443
- server url:https://localhost:9443/cas-server
- No Such User Redirect URL:https://localhost:8443
Salviamo la configurazione e facciamo logout.
Come ultimo passo dobbiamo configurare la webapp di cas.
Copiamo il war di cas nella webapp di tomcat 8 e startiamo il server.
Appena il war viene scompattato stoppiamo il tomcat.
Ora modifichiamo i file di proprty del cas che si trovano in tomcat/webapp/cas-server/classes
Editiamo boostrap.property
Commentiamo la riga seguente
spring.cloud.config.server.native.searchLocations=file:///etc/cas/config
Ora editiamo
application.property
sovrascirvere il contennuto del file con le property seguenti (adattando i paramentri di connessione ad ldap)
Modifichiamo la sezione relativa al logging in questo modo
##
# CAS Log4j Configuration
#
#logging.config=file:/etc/cas/log4j2.xml
logging.config=classpath:log4j2.xml
#server.context-parameters.isLog4jAutoInitializationDisabled=true
Disabiltiamo gli utenti statici di cas (in caso contrario funzionerebbe solo con questi)
##
# CAS Authentication Credentials
#
cas.authn.accept.users=
Configuriamo le chiavi di encrypt per i cookie. (Se non le configuriamo al primo start di cas verranno generate e scritte nei log)
# CAS SSO Cookie Generation & Security
# See https://github.com/mitreid-connect/json-web-key-generator
#
# Do note that the following settings MUST be generated per deployment.
#
# Defaults at spring-configuration/ticketGrantingTicketCookieGenerator.xml
# The encryption secret key. By default, must be a octet string of size 256.
tgc.encryption.key=f0ScJSsOIEzZf5Llhmq-xc9GA9oHBHtQmoRLbCxKFUc
# The signing secret key. By default, must be a octet string of size 512.
tgc.signing.key=tPw2L0W3fyPpZUEiIi-qKz6RAt4FuHsqUPJblBNUfBPWkrDtAJaMFOYOoCqrUapf6pDOke8ApFAO4itTQBvMag
Finalemente abbiamo finito tutte le configurazioni e possiamo startare il nostro server cas.
Purtroppo Liferay, ha un bug sul primo accesso, dovuto ad una doppia validazione del ticket generato dai termini d'uso e dal cambio password.
Quindi ho dovuto modificare tramite un hook due jsp
terms_of_use.jsp
in cui ho modificato il primo statement if
all'interno della jsp in questo modo
if (referer.equals(themeDisplay.getPathMain() + "/portal/update_terms_of_use")) {
referer = themeDisplay.getPathMain() + "?doAsUserId=" + themeDisplay.getDoAsUserId();
} else if (referer.contains("ticket")) {
referer = HttpUtil.removeParameter(referer, "ticket");
}
e in modo speculare ho modificato
update_password.jsp
if (referer.startsWith(themeDisplay.getPathMain() + "/portal/update_password") && Validator.isNotNull(ticketKey)) {
referer = themeDisplay.getPathMain();
}else if (referer.contains("ticket")) {
Prevents CAS ticket to be validated twice
referer = HttpUtil.removeParameter(referer, "ticket");
}
Dopo paver deployato l'hook colleghiamoci a https://localhost:8443
- clicchiamo su sign-in (non dalla portlet) per venire reindirizzati su cas
- inseriamo le nostre credenziali
se tutto è andato a buon fine verremo reindirizzati su liferay che ci chiederà di accettare i termini d'uso e cambiare la password.