]> git.argeo.org Git - lgpl/argeo-commons.git/blob - CmsSessionImpl.java
734b874efff24743c9dc998f5c6aab0db9d67f16
[lgpl/argeo-commons.git] / CmsSessionImpl.java
1 package org.argeo.cms.internal.auth;
2
3 import java.io.Serializable;
4 import java.security.AccessControlContext;
5 import java.security.AccessController;
6 import java.security.PrivilegedAction;
7 import java.time.ZonedDateTime;
8 import java.util.Collection;
9 import java.util.HashMap;
10 import java.util.Hashtable;
11 import java.util.Locale;
12 import java.util.Map;
13 import java.util.Set;
14 import java.util.UUID;
15
16 import javax.crypto.SecretKey;
17 import javax.naming.InvalidNameException;
18 import javax.naming.ldap.LdapName;
19 import javax.security.auth.Subject;
20 import javax.security.auth.login.LoginContext;
21 import javax.security.auth.login.LoginException;
22 import javax.security.auth.x500.X500Principal;
23
24 import org.apache.commons.logging.Log;
25 import org.apache.commons.logging.LogFactory;
26 import org.argeo.api.NodeConstants;
27 import org.argeo.api.security.NodeSecurityUtils;
28 import org.argeo.cms.auth.CmsSession;
29 import org.osgi.framework.BundleContext;
30 import org.osgi.framework.FrameworkUtil;
31 import org.osgi.framework.InvalidSyntaxException;
32 import org.osgi.framework.ServiceReference;
33 import org.osgi.framework.ServiceRegistration;
34 import org.osgi.service.useradmin.Authorization;
35
36 /** Default CMS session implementation. */
37 public class CmsSessionImpl implements CmsSession, Serializable {
38 private static final long serialVersionUID = 1867719354246307225L;
39 private final static BundleContext bc = FrameworkUtil.getBundle(CmsSessionImpl.class).getBundleContext();
40 private final static Log log = LogFactory.getLog(CmsSessionImpl.class);
41
42 // private final Subject initialSubject;
43 private transient AccessControlContext accessControlContext;
44 private final UUID uuid;
45 private final String localSessionId;
46 private Authorization authorization;
47 private final LdapName userDn;
48 private final boolean anonymous;
49
50 private final ZonedDateTime creationTime;
51 private ZonedDateTime end;
52 private final Locale locale;
53
54 private ServiceRegistration<CmsSession> serviceRegistration;
55
56 private Map<String, Object> views = new HashMap<>();
57
58 public CmsSessionImpl(Subject initialSubject, Authorization authorization, Locale locale, String localSessionId) {
59 this.creationTime = ZonedDateTime.now();
60 this.locale = locale;
61 this.accessControlContext = Subject.doAs(initialSubject, new PrivilegedAction<AccessControlContext>() {
62
63 @Override
64 public AccessControlContext run() {
65 return AccessController.getContext();
66 }
67
68 });
69 // this.initialSubject = initialSubject;
70 this.localSessionId = localSessionId;
71 this.authorization = authorization;
72 if (authorization.getName() != null)
73 try {
74 this.userDn = new LdapName(authorization.getName());
75 this.anonymous = false;
76 } catch (InvalidNameException e) {
77 throw new IllegalArgumentException("Invalid user name " + authorization.getName(), e);
78 }
79 else {
80 this.userDn = NodeSecurityUtils.ROLE_ANONYMOUS_NAME;
81 this.anonymous = true;
82 }
83 this.uuid = UUID.randomUUID();
84 // register as service
85 Hashtable<String, String> props = new Hashtable<>();
86 props.put(CmsSession.USER_DN, userDn.toString());
87 props.put(CmsSession.SESSION_UUID, uuid.toString());
88 props.put(CmsSession.SESSION_LOCAL_ID, localSessionId);
89 serviceRegistration = bc.registerService(CmsSession.class, this, props);
90 }
91
92 public void close() {
93 end = ZonedDateTime.now();
94 serviceRegistration.unregister();
95
96
97 try {
98 LoginContext lc;
99 if (isAnonymous()) {
100 lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_ANONYMOUS, getSubject());
101 } else {
102 lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, getSubject());
103 }
104 lc.logout();
105 } catch (LoginException e) {
106 log.warn("Could not logout " + getSubject() + ": " + e);
107 } finally {
108 accessControlContext = null;
109 }
110 log.debug("Closed " + this);
111 }
112
113 public Subject getSubject() {
114 return Subject.getSubject(accessControlContext);
115 }
116
117 public Set<SecretKey> getSecretKeys() {
118 checkValid();
119 return getSubject().getPrivateCredentials(SecretKey.class);
120 }
121
122 @Override
123 public boolean isValid() {
124 return !isClosed();
125 }
126
127 private void checkValid() {
128 if (!isValid())
129 throw new IllegalStateException("CMS session " + uuid + " is not valid since " + end);
130 }
131
132 final protected boolean isClosed() {
133 return getEnd() != null;
134 }
135
136 @Override
137 public Authorization getAuthorization() {
138 checkValid();
139 return authorization;
140 }
141
142 @Override
143 public UUID getUuid() {
144 return uuid;
145 }
146
147 @Override
148 public LdapName getUserDn() {
149 return userDn;
150 }
151
152 @Override
153 public String getUserRole() {
154 return new X500Principal(authorization.getName()).getName();
155 }
156
157 @Override
158 public String getLocalId() {
159 return localSessionId;
160 }
161
162 @Override
163 public boolean isAnonymous() {
164 return anonymous;
165 }
166
167 @Override
168 public Locale getLocale() {
169 return locale;
170 }
171
172 @Override
173 public ZonedDateTime getCreationTime() {
174 return creationTime;
175 }
176
177 @Override
178 public ZonedDateTime getEnd() {
179 return end;
180 }
181
182 @Override
183 public void registerView(String uid, Object view) {
184 checkValid();
185 if (views.containsKey(uid))
186 throw new IllegalArgumentException("View " + uid + " is already registered.");
187 views.put(uid, view);
188 }
189
190 public String toString() {
191 return "CMS Session " + userDn + " local=" + localSessionId + ", uuid=" + uuid;
192 }
193
194 public static CmsSessionImpl getByLocalId(String localId) {
195 Collection<ServiceReference<CmsSession>> sr;
196 try {
197 sr = bc.getServiceReferences(CmsSession.class, "(" + CmsSession.SESSION_LOCAL_ID + "=" + localId + ")");
198 } catch (InvalidSyntaxException e) {
199 throw new IllegalArgumentException("Cannot get CMS session for id " + localId, e);
200 }
201 ServiceReference<CmsSession> cmsSessionRef;
202 if (sr.size() == 1) {
203 cmsSessionRef = sr.iterator().next();
204 return (CmsSessionImpl) bc.getService(cmsSessionRef);
205 } else if (sr.size() == 0) {
206 return null;
207 } else
208 throw new IllegalStateException(sr.size() + " CMS sessions registered for " + localId);
209
210 }
211
212 public static CmsSessionImpl getByUuid(Object uuid) {
213 Collection<ServiceReference<CmsSession>> sr;
214 try {
215 sr = bc.getServiceReferences(CmsSession.class, "(" + CmsSession.SESSION_UUID + "=" + uuid + ")");
216 } catch (InvalidSyntaxException e) {
217 throw new IllegalArgumentException("Cannot get CMS session for uuid " + uuid, e);
218 }
219 ServiceReference<CmsSession> cmsSessionRef;
220 if (sr.size() == 1) {
221 cmsSessionRef = sr.iterator().next();
222 return (CmsSessionImpl) bc.getService(cmsSessionRef);
223 } else if (sr.size() == 0) {
224 return null;
225 } else
226 throw new IllegalStateException(sr.size() + " CMS sessions registered for " + uuid);
227
228 }
229
230 public static void closeInvalidSessions() {
231 Collection<ServiceReference<CmsSession>> srs;
232 try {
233 srs = bc.getServiceReferences(CmsSession.class, null);
234 for (ServiceReference<CmsSession> sr : srs) {
235 CmsSession cmsSession = bc.getService(sr);
236 if (!cmsSession.isValid()) {
237 ((CmsSessionImpl) cmsSession).close();
238 if (log.isDebugEnabled())
239 log.debug("Closed expired CMS session " + cmsSession);
240 }
241 }
242 } catch (InvalidSyntaxException e) {
243 throw new IllegalArgumentException("Cannot get CMS sessions", e);
244 }
245 }
246 }