1
18 package io.undertow.servlet.handlers.security;
19
20 import io.undertow.security.api.AuthenticatedSessionManager;
21 import io.undertow.security.api.AuthenticatedSessionManager.AuthenticatedSession;
22 import io.undertow.security.api.NotificationReceiver;
23 import io.undertow.security.api.SecurityContext;
24 import io.undertow.security.api.SecurityNotification;
25 import io.undertow.security.api.SecurityNotification.EventType;
26 import io.undertow.server.HttpHandler;
27 import io.undertow.server.HttpServerExchange;
28 import io.undertow.server.session.Session;
29 import io.undertow.servlet.handlers.ServletRequestContext;
30 import io.undertow.servlet.spec.HttpSessionImpl;
31 import io.undertow.servlet.spec.ServletContextImpl;
32 import io.undertow.servlet.util.SavedRequest;
33
34 import java.security.AccessController;
35
36 import javax.servlet.http.HttpSession;
37
38
46 public class CachedAuthenticatedSessionHandler implements HttpHandler {
47
48 public static final String ATTRIBUTE_NAME = CachedAuthenticatedSessionHandler.class.getName() + ".AuthenticatedSession";
49
50 public static final String NO_ID_CHANGE_REQUIRED = CachedAuthenticatedSessionHandler.class.getName() + ".NoIdChangeRequired";
51
52 private final NotificationReceiver NOTIFICATION_RECEIVER = new SecurityNotificationReceiver();
53 private final AuthenticatedSessionManager SESSION_MANAGER = new ServletAuthenticatedSessionManager();
54
55 private final HttpHandler next;
56 private final ServletContextImpl servletContext;
57
58 public CachedAuthenticatedSessionHandler(final HttpHandler next, final ServletContextImpl servletContext) {
59 this.next = next;
60 this.servletContext = servletContext;
61 }
62
63
64 @Override
65 public void handleRequest(HttpServerExchange exchange) throws Exception {
66 SecurityContext securityContext = exchange.getSecurityContext();
67 securityContext.registerNotificationReceiver(NOTIFICATION_RECEIVER);
68
69 HttpSession session = servletContext.getSession(exchange, false);
70
71
72 if (session != null) {
73 exchange.putAttachment(AuthenticatedSessionManager.ATTACHMENT_KEY, SESSION_MANAGER);
74 SavedRequest.tryRestoreRequest(exchange, session);
75 }
76
77 next.handleRequest(exchange);
78 }
79
80 private class SecurityNotificationReceiver implements NotificationReceiver {
81
82 @Override
83 public void handleNotification(SecurityNotification notification) {
84 EventType eventType = notification.getEventType();
85 HttpSessionImpl httpSession = servletContext.getSession(notification.getExchange(), false);
86 switch (eventType) {
87 case AUTHENTICATED:
88 if (isCacheable(notification)) {
89 if(servletContext.getDeployment().getDeploymentInfo().isChangeSessionIdOnLogin()) {
90 if (httpSession != null) {
91 Session session = underlyingSession(httpSession);
92 if (!httpSession.isNew() &&
93 !httpSession.isInvalid() &&
94 session.getAttribute(NO_ID_CHANGE_REQUIRED) == null) {
95 ServletRequestContext src = notification.getExchange().getAttachment(ServletRequestContext.ATTACHMENT_KEY);
96 src.getOriginalRequest().changeSessionId();
97 }
98 if(session.getAttribute(NO_ID_CHANGE_REQUIRED) == null) {
99 session.setAttribute(NO_ID_CHANGE_REQUIRED, true);
100 }
101 }
102 }
103 if(httpSession == null) {
104 httpSession = servletContext.getSession(notification.getExchange(), true);
105 }
106 Session session = underlyingSession(httpSession);
107
108
109
110
111 session.setAttribute(ATTRIBUTE_NAME,
112 new AuthenticatedSession(notification.getAccount(), notification.getMechanism()));
113 }
114 break;
115 case LOGGED_OUT:
116 if (httpSession != null) {
117 Session session = underlyingSession(httpSession);
118 session.removeAttribute(ATTRIBUTE_NAME);
119 session.removeAttribute(NO_ID_CHANGE_REQUIRED);
120 }
121 break;
122 }
123 }
124
125 }
126
127 protected Session underlyingSession(HttpSessionImpl httpSession) {
128 Session session;
129 if (System.getSecurityManager() == null) {
130 session = httpSession.getSession();
131 } else {
132 session = AccessController.doPrivileged(new HttpSessionImpl.UnwrapSessionAction(httpSession));
133 }
134 return session;
135 }
136
137 private class ServletAuthenticatedSessionManager implements AuthenticatedSessionManager {
138
139 @Override
140 public AuthenticatedSession lookupSession(HttpServerExchange exchange) {
141 HttpSessionImpl httpSession = servletContext.getSession(exchange, false);
142 if (httpSession != null) {
143 Session session = underlyingSession(httpSession);
144 return (AuthenticatedSession) session.getAttribute(ATTRIBUTE_NAME);
145 }
146 return null;
147 }
148
149 @Override
150 public void clearSession(HttpServerExchange exchange) {
151 HttpSessionImpl httpSession = servletContext.getSession(exchange, false);
152 if (httpSession != null) {
153 Session session = underlyingSession(httpSession);
154 session.removeAttribute(ATTRIBUTE_NAME);
155 }
156 }
157
158 }
159
160 private boolean isCacheable(final SecurityNotification notification) {
161 return notification.isProgramatic() || notification.isCachingRequired();
162 }
163
164 }
165