From 66898c9b1c3495ff7a0ed5e1adf34c28e40dc4e8 Mon Sep 17 00:00:00 2001
From: Gabriel Landais <glandais@kereval.com>
Date: Mon, 31 Jan 2011 14:33:37 +0000
Subject: [PATCH] Using CAS

git-svn-id: https://scm.gforge.inria.fr/authscm/ycadoret/svn/gazelle/Maven/gazelle-proxy/trunk@19913 356b4b1a-1d2b-0410-8bf1-ffa24008f01e
---
 gazelle-proxy-ejb/pom.xml                     |   9 +-
 .../proxy/action/ChannelManagerBean.java      |  21 +--
 .../proxy/action/ChannelManagerLocal.java     |   4 -
 .../ihe/gazelle/proxy/util/SSOIdentity.java   | 151 ++++++++++++++++++
 .../src/main/webapp/WEB-INF/web.xml           |  57 +++++--
 .../src/main/webapp/cas/home.xhtml            |  15 ++
 .../src/main/webapp/channels.xhtml            |  15 +-
 .../src/main/webapp/layout/menu.xhtml         |  14 +-
 .../src/main/webapp/newchannel.xhtml          |   7 -
 pom.xml                                       |  41 +----
 10 files changed, 258 insertions(+), 76 deletions(-)
 create mode 100644 gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/util/SSOIdentity.java
 create mode 100644 gazelle-proxy-war/src/main/webapp/cas/home.xhtml

diff --git a/gazelle-proxy-ejb/pom.xml b/gazelle-proxy-ejb/pom.xml
index 4b3964a2..ee088621 100644
--- a/gazelle-proxy-ejb/pom.xml
+++ b/gazelle-proxy-ejb/pom.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 
 	<parent>
 		<groupId>net.ihe.gazelle.proxy</groupId>
@@ -102,7 +103,11 @@
 			<artifactId>persistence-api</artifactId>
 			<scope>provided</scope>
 		</dependency>
-
+		<dependency>
+			<groupId>org.jasig.cas</groupId>
+			<artifactId>cas-client-core</artifactId>
+			<version>3.1.10</version>
+		</dependency>
 
 	</dependencies>
 </project>
diff --git a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/ChannelManagerBean.java b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/ChannelManagerBean.java
index 07ba012d..ac8383a1 100644
--- a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/ChannelManagerBean.java
+++ b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/ChannelManagerBean.java
@@ -45,6 +45,7 @@ import org.jboss.seam.annotations.Scope;
 import org.jboss.seam.faces.FacesMessages;
 import org.jboss.seam.international.StatusMessage;
 import org.jboss.seam.log.Log;
+import org.jboss.seam.security.Identity;
 
 /**
  * 
@@ -90,6 +91,9 @@ public class ChannelManagerBean implements ChannelManagerLocal, Serializable {
 	@In
 	private EntityManager entityManager;
 
+	@In
+	Identity identity;
+
 	private PushEventListener listener;
 
 	private Boolean autoUpdate = Boolean.TRUE;
@@ -98,7 +102,6 @@ public class ChannelManagerBean implements ChannelManagerLocal, Serializable {
 
 	private Date lastRefreshDate;
 
-	private String password;
 	private ChannelType messageType = ChannelType.HTTP;
 	private Integer proxyPort;
 	private String responderIP;
@@ -173,10 +176,6 @@ public class ChannelManagerBean implements ChannelManagerLocal, Serializable {
 		return onlyStarted;
 	}
 
-	public String getPassword() {
-		return password;
-	}
-
 	public Integer getProxyPort() {
 		return proxyPort;
 	}
@@ -250,10 +249,6 @@ public class ChannelManagerBean implements ChannelManagerLocal, Serializable {
 		this.onlyStarted = onlyStarted;
 	}
 
-	public void setPassword(String password) {
-		this.password = password;
-	}
-
 	public void setProxyPort(Integer proxyPort) {
 		this.proxyPort = proxyPort;
 	}
@@ -279,14 +274,14 @@ public class ChannelManagerBean implements ChannelManagerLocal, Serializable {
 	}
 
 	public void startChannel() {
-		if ("gazelle".equals(password)) {
+		if (identity.hasRole("admin_role")) {
 			Object config = null;
 			if (getMessageType() == ChannelType.HTTPS) {
 				config = getTlsConfig();
 			}
 			createAndStartChannel("", getProxyPort(), getResponderIP(), getResponderPort(), getMessageType(), config);
 		} else {
-			FacesMessages.instance().add("Wrong password");
+			FacesMessages.instance().add("Wrong role");
 		}
 	}
 
@@ -298,7 +293,7 @@ public class ChannelManagerBean implements ChannelManagerLocal, Serializable {
 	}
 
 	public void stopChannel(int localPort) {
-		if ("gazelle".equals(password)) {
+		if (identity.hasRole("admin_role")) {
 			try {
 				proxyBean.stopChannel(localPort);
 				FacesMessages.instance().add(StatusMessage.Severity.INFO, "Channel successfully stopped");
@@ -307,7 +302,7 @@ public class ChannelManagerBean implements ChannelManagerLocal, Serializable {
 						"Failed to stop channel : " + ExceptionUtils.getFullStackTrace(e));
 			}
 		} else {
-			FacesMessages.instance().add("Wrong password");
+			FacesMessages.instance().add("Wrong role");
 		}
 	}
 
diff --git a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/ChannelManagerLocal.java b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/ChannelManagerLocal.java
index 8ae7513f..e0775b8c 100644
--- a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/ChannelManagerLocal.java
+++ b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/action/ChannelManagerLocal.java
@@ -46,8 +46,6 @@ public interface ChannelManagerLocal {
 
 	public abstract List<ChannelType> getMessageTypes();
 
-	public abstract String getPassword();
-
 	public abstract Integer getProxyPort();
 
 	public abstract String getResponderIP();
@@ -70,8 +68,6 @@ public interface ChannelManagerLocal {
 
 	public abstract void setMessageType(ChannelType messageType);
 
-	public abstract void setPassword(String password);
-
 	public abstract void setProxyPort(Integer proxyPort);
 
 	public abstract void setResponderIP(String responderIP);
diff --git a/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/util/SSOIdentity.java b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/util/SSOIdentity.java
new file mode 100644
index 00000000..0e66338c
--- /dev/null
+++ b/gazelle-proxy-ejb/src/main/java/net/ihe/gazelle/proxy/util/SSOIdentity.java
@@ -0,0 +1,151 @@
+package net.ihe.gazelle.proxy.util;
+
+import static org.jboss.seam.annotations.Install.APPLICATION;
+
+import java.security.Principal;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.StringTokenizer;
+
+import javax.faces.context.FacesContext;
+import javax.persistence.EntityManager;
+import javax.persistence.NoResultException;
+import javax.servlet.http.HttpSession;
+
+import org.apache.commons.lang.StringUtils;
+import org.jasig.cas.client.authentication.AttributePrincipal;
+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.contexts.Contexts;
+import org.jboss.seam.core.Events;
+import org.jboss.seam.core.Expressions;
+import org.jboss.seam.core.Expressions.ValueExpression;
+import org.jboss.seam.log.LogProvider;
+import org.jboss.seam.log.Logging;
+import org.jboss.seam.security.Identity;
+import org.jboss.seam.security.management.IdentityManager;
+
+@Name("org.jboss.seam.security.identity")
+@Scope(ScopeType.SESSION)
+@Install(precedence = APPLICATION)
+@BypassInterceptors
+@Startup
+public class SSOIdentity extends Identity {
+
+	private static final long serialVersionUID = -631532323964539777L;
+
+	public static final String AUTHENTICATED_USER = "org.jboss.seam.security.management.authenticatedUser";
+	public static final String EVENT_USER_AUTHENTICATED = "org.jboss.seam.security.management.userAuthenticated";
+	private static final String SILENT_LOGIN = "org.jboss.seam.security.silentLogin";
+	private static final String CAS_ASSERTION = "_const_cas_assertion_";
+
+	private static final LogProvider log = Logging.getLogProvider(SSOIdentity.class);
+
+	private ValueExpression<EntityManager> entityManager;
+
+	public void initEntityManager() {
+		if (entityManager == null) {
+			entityManager = Expressions.instance().createValueExpression("#{entityManager}", EntityManager.class);
+		}
+	}
+
+	public EntityManager lookupEntityManager() {
+		return entityManager.getValue();
+	}
+
+	@Override
+	public void create() {
+		super.create();
+	}
+
+	@Override
+	public String login() {
+		initEntityManager();
+		log.info("Starting authentication");
+
+		try {
+
+			if (super.isLoggedIn()) {
+				// If authentication has already occurred during this request
+				// via a silent login, and login() is explicitly called then we
+				// still want to raise the LOGIN_SUCCESSFUL event, and then
+				// return.
+				if (Contexts.isEventContextActive() && Contexts.getEventContext().isSet(SILENT_LOGIN)) {
+					if (Events.exists())
+						Events.instance().raiseEvent(EVENT_LOGIN_SUCCESSFUL);
+					return "loggedIn";
+				}
+
+				if (Events.exists())
+					Events.instance().raiseEvent(EVENT_ALREADY_LOGGED_IN);
+				return "loggedIn";
+			}
+
+			preAuthenticate();
+			AttributePrincipal attributePrincipal = null;
+			Principal casPrincipal = getCASPrincipal();
+			if (casPrincipal instanceof AttributePrincipal) {
+				attributePrincipal = (AttributePrincipal) casPrincipal;
+			}
+
+			if (attributePrincipal == null) {
+				return super.login();
+			} else if (casPrincipal.getName() != null) {
+				preAuthenticate();
+
+				String username = casPrincipal.getName();
+
+				log.info("Found CAS principal for " + username + ": authenticated");
+				Map attributes = attributePrincipal.getAttributes();
+				Set<Map.Entry> entrySet = attributes.entrySet();
+				for (Map.Entry object : entrySet) {
+					log.info("       " + object.getKey() + " = " + object.getValue());
+				}
+
+				acceptExternallyAuthenticatedPrincipal(casPrincipal);
+				if (attributes != null && attributes.get("role_name") != null) {
+					String roles = (String) attributes.get("role_name");
+					roles = roles.substring(1, roles.length() - 1);
+					StringTokenizer st = new StringTokenizer(roles, ",");
+					String role;
+					while (st.hasMoreElements()) {
+						role = (String) st.nextElement();
+						role = StringUtils.trimToNull(role);
+						if (role != null) {
+							addRole(role);
+						}
+					}
+				}
+				getCredentials().setUsername(username);
+				postAuthenticate();
+				return "loggedIn";
+
+			}
+
+		} catch (Throwable e) {
+			unAuthenticate();
+			throw new RuntimeException(e);
+		}
+
+		return null;
+	}
+
+	private Principal getCASPrincipal() {
+		return (Principal) FacesContext.getCurrentInstance().getExternalContext().getUserPrincipal();
+	}
+
+	@Override
+	public boolean isLoggedIn() {
+		if (!super.isLoggedIn() && getCASPrincipal() != null) {
+			login();
+		}
+
+		return super.isLoggedIn();
+	}
+
+}
diff --git a/gazelle-proxy-war/src/main/webapp/WEB-INF/web.xml b/gazelle-proxy-war/src/main/webapp/WEB-INF/web.xml
index f4de1a19..8e3a3359 100644
--- a/gazelle-proxy-war/src/main/webapp/WEB-INF/web.xml
+++ b/gazelle-proxy-war/src/main/webapp/WEB-INF/web.xml
@@ -24,9 +24,7 @@
 		<param-value>.xhtml</param-value>
 	</context-param>
 
-	<!--
-		Ajax4jsf very important: http://jira.jboss.com/jira/browse/RF-1767
-	-->
+	<!-- Ajax4jsf very important: http://jira.jboss.com/jira/browse/RF-1767 -->
 	<filter>
 		<display-name>Ajax4jsf Filter</display-name>
 		<filter-name>ajax4jsf</filter-name>
@@ -75,10 +73,8 @@
 	</servlet-mapping>
 
 	<session-config>
-		<!--
-			Value is in minutes, must be less than SFSB time out which is 30
-			minutes by default
-		-->
+		<!-- Value is in minutes, must be less than SFSB time out which is 30 minutes 
+			by default -->
 		<session-timeout>20</session-timeout>
 	</session-config>
 
@@ -91,7 +87,48 @@
 		<auth-constraint />
 	</security-constraint>
 
-	<login-config>
-		<auth-method>BASIC</auth-method>
-	</login-config>
+	<!-- CAS -->
+	<filter>
+		<filter-name>CAS Authentication Filter</filter-name>
+		<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
+		<init-param>
+			<param-name>casServerLoginUrl</param-name>
+			<param-value>https://gazelle.ihe.net</param-value>
+		</init-param>
+		<init-param>
+			<param-name>service</param-name>
+			<param-value>${cas.service}</param-value>
+		</init-param>
+	</filter>
+	<filter>
+		<filter-name>CAS Validation Filter</filter-name>
+		<filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
+		<init-param>
+			<param-name>casServerUrlPrefix</param-name>
+			<param-value>https://gazelle.ihe.net</param-value>
+		</init-param>
+		<init-param>
+			<param-name>service</param-name>
+			<param-value>${cas.service}</param-value>
+		</init-param>
+	</filter>
+	<filter>
+		<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
+		<filter-class>org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
+	</filter>
+
+	<filter-mapping>
+		<filter-name>CAS Authentication Filter</filter-name>
+		<url-pattern>/cas/*</url-pattern>
+	</filter-mapping>
+
+	<filter-mapping>
+		<filter-name>CAS Validation Filter</filter-name>
+		<url-pattern>/*</url-pattern>
+	</filter-mapping>
+
+	<filter-mapping>
+		<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
+		<url-pattern>/*</url-pattern>
+	</filter-mapping>
 </web-app>
diff --git a/gazelle-proxy-war/src/main/webapp/cas/home.xhtml b/gazelle-proxy-war/src/main/webapp/cas/home.xhtml
new file mode 100644
index 00000000..6b47d2ac
--- /dev/null
+++ b/gazelle-proxy-war/src/main/webapp/cas/home.xhtml
@@ -0,0 +1,15 @@
+<!DOCTYPE composition PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+    "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<ui:composition xmlns="http://www.w3.org/1999/xhtml"
+	xmlns:s="http://jboss.com/products/seam/taglib"
+	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:a4j="http://richfaces.org/a4j"
+	xmlns:rich="http://richfaces.org/rich"
+	template="/layout/template.xhtml">
+
+	<ui:define name="body">
+		<h:outputText value="Signed in as: #{credentials.username}" />
+	</ui:define>
+</ui:composition>
diff --git a/gazelle-proxy-war/src/main/webapp/channels.xhtml b/gazelle-proxy-war/src/main/webapp/channels.xhtml
index bd7fb393..9ff161b5 100644
--- a/gazelle-proxy-war/src/main/webapp/channels.xhtml
+++ b/gazelle-proxy-war/src/main/webapp/channels.xhtml
@@ -112,7 +112,17 @@
 						</h:outputText>
 					</rich:column>
 
-					<rich:column>
+					<rich:column rendered="#{not s:hasRole('admin_role')}">
+						<f:facet name="header">
+							<h:outputText value="Channel state" />
+						</f:facet>
+
+						<h:outputText rendered="#{not currentChannel.started}"
+							value="Stopped" />
+						<h:outputText rendered="#{currentChannel.started}" value="Started" />
+					</rich:column>
+
+					<rich:column rendered="#{s:hasRole('admin_role')}">
 						<f:facet name="header">
 							<h:outputText value="Channel action" />
 						</f:facet>
@@ -145,9 +155,6 @@
 			<h:form id="stopForm">
 				<h:panelGrid columns="2">
 
-					<h:outputText value="Stop proxy password : " />
-					<h:inputSecret value="#{channelManagerBean.password}" />
-
 					<a4j:htmlCommandLink
 						action="Richfaces.hideModalPanel('stopPanel');" value="Cancel" />
 					<a4j:htmlCommandLink
diff --git a/gazelle-proxy-war/src/main/webapp/layout/menu.xhtml b/gazelle-proxy-war/src/main/webapp/layout/menu.xhtml
index 46a63ba7..87dfc6e2 100644
--- a/gazelle-proxy-war/src/main/webapp/layout/menu.xhtml
+++ b/gazelle-proxy-war/src/main/webapp/layout/menu.xhtml
@@ -8,11 +8,23 @@
 		<s:link id="menuChannels" view="/channels.xhtml" value="Channel list"
 			propagation="none" />
 		<s:link id="menuNewChannel" view="/newchannel.xhtml"
-			value="New channel" propagation="none" />
+			value="New channel" propagation="none"
+			rendered="#{s:hasRole('admin_role')}" />
 		<s:link id="menuMessagesList" view="/messages.xhtml"
 			value="Messages list" propagation="none" />
 
 		<a href="http://gazelle.ihe.net/?q=node/31">Help</a>
 	</rich:toolBarGroup>
 
+	<rich:toolBarGroup location="right">
+		<h:outputText id="menuWelcomeId"
+			value="signed in as: #{credentials.username}"
+			rendered="#{identity.loggedIn}" />
+		<s:link id="menuLoginCasId" view="/cas/home.xhtml" value="Login"
+			rendered="#{not identity.loggedIn}" propagation="none" />
+		<s:link id="menuLogoutId" view="/channels.xhtml"
+			action="#{identity.logout}" value="Logout"
+			rendered="#{identity.loggedIn}" propagation="none" />
+	</rich:toolBarGroup>
+
 </rich:toolBar>
diff --git a/gazelle-proxy-war/src/main/webapp/newchannel.xhtml b/gazelle-proxy-war/src/main/webapp/newchannel.xhtml
index f74c1aef..ab22f75f 100644
--- a/gazelle-proxy-war/src/main/webapp/newchannel.xhtml
+++ b/gazelle-proxy-war/src/main/webapp/newchannel.xhtml
@@ -61,13 +61,6 @@
 						<h:inputSecret value="#{channelManagerBean.serverPassword}" />
 					</s:decorate>
 
-					<s:decorate id="passwordDeco" template="/layout/edit.xhtml">
-						<ui:define name="label">Channel creation password</ui:define>
-						<h:inputSecret id="password"
-							value="#{channelManagerBean.password}" />
-					</s:decorate>
-					<s:decorate></s:decorate>
-
 				</h:panelGrid>
 				<h:commandButton value="Start"
 					action="#{channelManagerBean.startChannel()}" />
diff --git a/pom.xml b/pom.xml
index 75111891..95cb6814 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,5 +1,6 @@
 <?xml version="1.0" encoding="UTF-8"?>
-<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+	xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
 
 	<parent>
 		<groupId>org.jboss.seam</groupId>
@@ -117,7 +118,7 @@
 					</configuration>
 				</plugin>
 			</plugins>
-		</pluginManagement>		
+		</pluginManagement>
 	</build>
 
 	<dependencyManagement>
@@ -199,6 +200,7 @@
 			</activation>
 
 			<properties>
+				<cas.service>http://bento.irisa.fr:8080/GazelleProxyWS/</cas.service>
 				<!-- development mode (disable in production) -->
 				<seam.debug>false</seam.debug>
 
@@ -237,6 +239,7 @@
 			</activation>
 
 			<properties>
+				<cas.service>http://gazelle.ihe.net/GazelleProxyWS/</cas.service>
 				<!-- development mode (disable in production) -->
 				<seam.debug>false</seam.debug>
 
@@ -274,6 +277,7 @@
 				<activeByDefault>false</activeByDefault>
 			</activation>
 			<properties>
+				<cas.service>http://127.0.0.1:8080/GazelleProxyWS/</cas.service>
 				<!-- development mode (disable in production) -->
 				<seam.debug>true</seam.debug>
 
@@ -304,39 +308,6 @@
 			</properties>
 		</profile>
 
-		<profile>
-			<id>test</id>
-
-			<properties>
-				<!-- development mode (disable in production) -->
-				<seam.debug>false</seam.debug>
-
-				<!-- datasource configuration -->
-				<jdbc.connection.url>jdbc:postgresql://localhost/gazelle-proxy</jdbc.connection.url>
-				<jdbc.driver.class>org.postgresql.Driver</jdbc.driver.class>
-				<jdbc.user>gazelle</jdbc.user>
-				<jdbc.password>gazelle</jdbc.password>
-				<min.pool.size>1</min.pool.size>
-				<max.pool.size>10</max.pool.size>
-
-				<!-- package exploded war file -->
-				<exploded.war.file>false</exploded.war.file>
-
-				<!-- development mode (exclude in production) -->
-				<exclude.bootstrap>true</exclude.bootstrap>
-
-				<!-- persistence.xml configuration -->
-				<hibernate.dialect>
-					org.hibernate.dialect.PostgreSQLDialect
-				</hibernate.dialect>
-				<hibernate.hbm2ddl.auto>
-					validate
-				</hibernate.hbm2ddl.auto>
-				<hibernate.show_sql>
-					false
-				</hibernate.show_sql>
-			</properties>
-		</profile>
 	</profiles>
 	<modules>
 		<module>gazelle-proxy-netty</module>
-- 
GitLab