From 3bb43f417a124ae9baf7914281747fe52b03c251 Mon Sep 17 00:00:00 2001
From: Justin Richer <jricher@mitre.org>
Date: Mon, 15 Apr 2013 16:16:18 -0400
Subject: [PATCH] added auth time tracking

---
 .../connect/token/ConnectTokenEnhancer.java   | 18 +++++--
 .../web/AuthenticationTimeStamper.java        | 54 +++++++++++++++++++
 .../src/main/webapp/WEB-INF/user-context.xml  |  2 +-
 3 files changed, 70 insertions(+), 4 deletions(-)
 create mode 100644 openid-connect-server/src/main/java/org/mitre/openid/connect/web/AuthenticationTimeStamper.java

diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/token/ConnectTokenEnhancer.java b/openid-connect-server/src/main/java/org/mitre/openid/connect/token/ConnectTokenEnhancer.java
index 315c95e43..83d4bec49 100644
--- a/openid-connect-server/src/main/java/org/mitre/openid/connect/token/ConnectTokenEnhancer.java
+++ b/openid-connect-server/src/main/java/org/mitre/openid/connect/token/ConnectTokenEnhancer.java
@@ -15,16 +15,18 @@
  ******************************************************************************/
 package org.mitre.openid.connect.token;
 
-import java.security.NoSuchAlgorithmException;
 import java.util.Date;
 import java.util.Set;
 import java.util.UUID;
 
+import javax.servlet.http.HttpSession;
+
 import org.mitre.jwt.signer.service.JwtSigningAndValidationService;
 import org.mitre.oauth2.model.ClientDetailsEntity;
 import org.mitre.oauth2.model.OAuth2AccessTokenEntity;
 import org.mitre.oauth2.service.ClientDetailsEntityService;
 import org.mitre.openid.connect.config.ConfigurationPropertiesBean;
+import org.mitre.openid.connect.web.AuthenticationTimeStamper;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 import org.springframework.beans.factory.annotation.Autowired;
@@ -32,6 +34,8 @@ import org.springframework.security.oauth2.common.OAuth2AccessToken;
 import org.springframework.security.oauth2.provider.OAuth2Authentication;
 import org.springframework.security.oauth2.provider.token.TokenEnhancer;
 import org.springframework.stereotype.Service;
+import org.springframework.web.context.request.RequestContextHolder;
+import org.springframework.web.context.request.ServletRequestAttributes;
 
 import com.google.common.base.Strings;
 import com.google.common.collect.Lists;
@@ -100,9 +104,17 @@ public class ConnectTokenEnhancer implements TokenEnhancer {
 			JWTClaimsSet idClaims = new JWTClaimsSet();
 			
 			
-			idClaims.setCustomClaim("auth_time", new Date().getTime());
+			// get the auth time from the session
+			ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
+			if (attr != null) {
+				HttpSession session = attr.getRequest().getSession();
+				if (session != null) {
+					Date authTime = (Date) session.getAttribute(AuthenticationTimeStamper.AUTH_TIMESTAMP);
+					idClaims.setClaim("auth_time", authTime.getTime() / 1000);
+				}
+			}
 			
-			idClaims.setIssueTime(new Date());
+			idClaims.setIssueTime(claims.getIssueTime());
 			
 			if (client.getIdTokenValiditySeconds() != null) {
 				Date expiration = new Date(System.currentTimeMillis() + (client.getIdTokenValiditySeconds() * 1000L));
diff --git a/openid-connect-server/src/main/java/org/mitre/openid/connect/web/AuthenticationTimeStamper.java b/openid-connect-server/src/main/java/org/mitre/openid/connect/web/AuthenticationTimeStamper.java
new file mode 100644
index 000000000..a5924529e
--- /dev/null
+++ b/openid-connect-server/src/main/java/org/mitre/openid/connect/web/AuthenticationTimeStamper.java
@@ -0,0 +1,54 @@
+/**
+ * 
+ */
+package org.mitre.openid.connect.web;
+
+import java.io.IOException;
+import java.util.Date;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.servlet.http.HttpSession;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.web.authentication.AuthenticationSuccessHandler;
+import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
+import org.springframework.stereotype.Component;
+
+/**
+ * This class sets a timestamp on the current HttpSession 
+ * when someone successfully authenticates. 
+ * 
+ * @author jricher
+ *
+ */
+@Component("authenticationTimeStamper")
+public class AuthenticationTimeStamper extends SavedRequestAwareAuthenticationSuccessHandler {
+
+	private static Logger logger = LoggerFactory.getLogger(AuthenticationTimeStamper.class);
+	
+	public static final String AUTH_TIMESTAMP = "AUTH_TIMESTAMP";
+	
+	/**
+	 * Set the timestamp on the session to mark when the authentication happened, 
+	 * useful for calculating authentication age.
+	 */
+	@Override
+	public void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response, Authentication authentication) throws IOException, ServletException {
+
+		Date authTimestamp = new Date();
+		
+		HttpSession session = request.getSession();
+
+		session.setAttribute(AUTH_TIMESTAMP, authTimestamp);
+
+		logger.info("Successful Authentication at " + authTimestamp.toString());
+		
+		super.onAuthenticationSuccess(request, response, authentication);
+		
+	}
+
+}
diff --git a/openid-connect-server/src/main/webapp/WEB-INF/user-context.xml b/openid-connect-server/src/main/webapp/WEB-INF/user-context.xml
index e47cfca7d..b30f5b38c 100644
--- a/openid-connect-server/src/main/webapp/WEB-INF/user-context.xml
+++ b/openid-connect-server/src/main/webapp/WEB-INF/user-context.xml
@@ -27,7 +27,7 @@
 	</security:http>
 		
 	<security:http disable-url-rewriting="true" use-expressions="true"> 
-		<security:form-login login-page="/login" authentication-failure-url="/login?error=failure" />
+		<security:form-login login-page="/login" authentication-failure-url="/login?error=failure" authentication-success-handler-ref="authenticationTimeStamper" />
 		<security:intercept-url pattern="/**" access="permitAll" />
 		<security:custom-filter ref="resourceServerFilter" before="PRE_AUTH_FILTER" />
 		<security:logout logout-url="/logout" />