]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/internal/auth/CmsSessionImpl.java
SLF4J implementation.
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / internal / auth / 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.cms.CmsSession;
28 import org.argeo.api.security.NodeSecurityUtils;
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 try {
97 LoginContext lc;
98 if (isAnonymous()) {
99 lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_ANONYMOUS, getSubject());
100 } else {
101 lc = new LoginContext(NodeConstants.LOGIN_CONTEXT_USER, getSubject());
102 }
103 lc.logout();
104 } catch (LoginException e) {
105 log.warn("Could not logout " + getSubject() + ": " + e);
106 } finally {
107 accessControlContext = null;
108 }
109 log.debug("Closed " + this);
110 }
111
112 public Subject getSubject() {
113 return Subject.getSubject(accessControlContext);
114 }
115
116 public Set<SecretKey> getSecretKeys() {
117 checkValid();
118 return getSubject().getPrivateCredentials(SecretKey.class);
119 }
120
121 @Override
122 public boolean isValid() {
123 return !isClosed();
124 }
125
126 private void checkValid() {
127 if (!isValid())
128 throw new IllegalStateException("CMS session " + uuid + " is not valid since " + end);
129 }
130
131 final protected boolean isClosed() {
132 return getEnd() != null;
133 }
134
135 public Authorization getAuthorization() {
136 checkValid();
137 return authorization;
138 }
139
140 @Override
141 public String getDisplayName() {
142 return authorization.toString();
143 }
144
145 @Override
146 public UUID getUuid() {
147 return uuid;
148 }
149
150 @Override
151 public LdapName getUserDn() {
152 return userDn;
153 }
154
155 @Override
156 public String getUserRole() {
157 return new X500Principal(authorization.getName()).getName();
158 }
159
160 @Override
161 public String getLocalId() {
162 return localSessionId;
163 }
164
165 @Override
166 public boolean isAnonymous() {
167 return anonymous;
168 }
169
170 @Override
171 public Locale getLocale() {
172 return locale;
173 }
174
175 @Override
176 public ZonedDateTime getCreationTime() {
177 return creationTime;
178 }
179
180 @Override
181 public ZonedDateTime getEnd() {
182 return end;
183 }
184
185 @Override
186 public void registerView(String uid, Object view) {
187 checkValid();
188 if (views.containsKey(uid))
189 throw new IllegalArgumentException("View " + uid + " is already registered.");
190 views.put(uid, view);
191 }
192
193 public String toString() {
194 return "CMS Session " + userDn + " local=" + localSessionId + ", uuid=" + uuid;
195 }
196
197 public static CmsSessionImpl getByLocalId(String localId) {
198 Collection<ServiceReference<CmsSession>> sr;
199 try {
200 sr = bc.getServiceReferences(CmsSession.class, "(" + CmsSession.SESSION_LOCAL_ID + "=" + localId + ")");
201 } catch (InvalidSyntaxException e) {
202 throw new IllegalArgumentException("Cannot get CMS session for id " + localId, e);
203 }
204 ServiceReference<CmsSession> cmsSessionRef;
205 if (sr.size() == 1) {
206 cmsSessionRef = sr.iterator().next();
207 return (CmsSessionImpl) bc.getService(cmsSessionRef);
208 } else if (sr.size() == 0) {
209 return null;
210 } else
211 throw new IllegalStateException(sr.size() + " CMS sessions registered for " + localId);
212
213 }
214
215 public static CmsSessionImpl getByUuid(Object uuid) {
216 Collection<ServiceReference<CmsSession>> sr;
217 try {
218 sr = bc.getServiceReferences(CmsSession.class, "(" + CmsSession.SESSION_UUID + "=" + uuid + ")");
219 } catch (InvalidSyntaxException e) {
220 throw new IllegalArgumentException("Cannot get CMS session for uuid " + uuid, e);
221 }
222 ServiceReference<CmsSession> cmsSessionRef;
223 if (sr.size() == 1) {
224 cmsSessionRef = sr.iterator().next();
225 return (CmsSessionImpl) bc.getService(cmsSessionRef);
226 } else if (sr.size() == 0) {
227 return null;
228 } else
229 throw new IllegalStateException(sr.size() + " CMS sessions registered for " + uuid);
230
231 }
232
233 public static void closeInvalidSessions() {
234 Collection<ServiceReference<CmsSession>> srs;
235 try {
236 srs = bc.getServiceReferences(CmsSession.class, null);
237 for (ServiceReference<CmsSession> sr : srs) {
238 CmsSession cmsSession = bc.getService(sr);
239 if (!cmsSession.isValid()) {
240 ((CmsSessionImpl) cmsSession).close();
241 if (log.isDebugEnabled())
242 log.debug("Closed expired CMS session " + cmsSession);
243 }
244 }
245 } catch (InvalidSyntaxException e) {
246 throw new IllegalArgumentException("Cannot get CMS sessions", e);
247 }
248 }
249 }