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