1 package org
.argeo
.cms
.internal
.auth
;
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
;
17 import java
.util
.UUID
;
18 import java
.util
.function
.Consumer
;
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
;
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
;
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);
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
;
54 private final ZonedDateTime creationTime
;
55 private ZonedDateTime end
;
56 private final Locale locale
;
58 private ServiceRegistration
<CmsSession
> serviceRegistration
;
60 private Map
<String
, Object
> views
= new HashMap
<>();
62 private List
<Consumer
<CmsSession
>> onCloseCallbacks
= Collections
.synchronizedList(new ArrayList
<>());
64 public CmsSessionImpl(Subject initialSubject
, Authorization authorization
, Locale locale
, String localSessionId
) {
65 this.creationTime
= ZonedDateTime
.now();
67 this.accessControlContext
= Subject
.doAs(initialSubject
, new PrivilegedAction
<AccessControlContext
>() {
70 public AccessControlContext
run() {
71 return AccessController
.getContext();
75 // this.initialSubject = initialSubject;
76 this.localSessionId
= localSessionId
;
77 this.authorization
= authorization
;
78 if (authorization
.getName() != null)
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
);
86 this.userDn
= NodeSecurityUtils
.ROLE_ANONYMOUS_NAME
;
87 this.anonymous
= true;
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);
100 end
= ZonedDateTime
.now();
101 CmsContextImpl
.getCmsContext().unregisterCmsSession(this);
102 // serviceRegistration.unregister();
104 for (Consumer
<CmsSession
> onClose
: onCloseCallbacks
) {
105 onClose
.accept(this);
111 lc
= new LoginContext(CmsAuth
.LOGIN_CONTEXT_ANONYMOUS
, getSubject());
113 lc
= new LoginContext(CmsAuth
.LOGIN_CONTEXT_USER
, getSubject());
116 } catch (LoginException e
) {
117 log
.warn("Could not logout " + getSubject() + ": " + e
);
119 accessControlContext
= null;
121 log
.debug("Closed " + this);
125 public void addOnCloseCallback(Consumer
<CmsSession
> onClose
) {
126 onCloseCallbacks
.add(onClose
);
129 public Subject
getSubject() {
130 return Subject
.getSubject(accessControlContext
);
133 public Set
<SecretKey
> getSecretKeys() {
135 return getSubject().getPrivateCredentials(SecretKey
.class);
139 public boolean isValid() {
143 private void checkValid() {
145 throw new IllegalStateException("CMS session " + uuid
+ " is not valid since " + end
);
148 final protected boolean isClosed() {
149 return getEnd() != null;
152 public Authorization
getAuthorization() {
154 return authorization
;
158 public String
getDisplayName() {
159 return authorization
.toString();
163 public UUID
getUuid() {
168 public LdapName
getUserDn() {
173 public String
getUserRole() {
174 return new X500Principal(authorization
.getName()).getName();
178 public String
getLocalId() {
179 return localSessionId
;
183 public boolean isAnonymous() {
188 public Locale
getLocale() {
193 public ZonedDateTime
getCreationTime() {
198 public ZonedDateTime
getEnd() {
203 public void registerView(String uid
, Object view
) {
205 if (views
.containsKey(uid
))
206 throw new IllegalArgumentException("View " + uid
+ " is already registered.");
207 views
.put(uid
, view
);
210 public String
toString() {
211 return "CMS Session " + userDn
+ " localId=" + localSessionId
+ ", uuid=" + uuid
;
214 // public static CmsSessionImpl getByLocalId(String localId) {
215 // Collection<ServiceReference<CmsSession>> sr;
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);
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) {
228 // throw new IllegalStateException(sr.size() + " CMS sessions registered for " + localId);
232 // public static CmsSessionImpl getByUuid(Object uuid) {
233 // Collection<ServiceReference<CmsSession>> sr;
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);
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) {
246 // throw new IllegalStateException(sr.size() + " CMS sessions registered for " + uuid);
250 // public static void closeInvalidSessions() {
251 // Collection<ServiceReference<CmsSession>> srs;
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);
262 // } catch (InvalidSyntaxException e) {
263 // throw new IllegalArgumentException("Cannot get CMS sessions", e);