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
.security
.NodeSecurityUtils
;
32 import org
.osgi
.framework
.BundleContext
;
33 import org
.osgi
.framework
.FrameworkUtil
;
34 import org
.osgi
.framework
.InvalidSyntaxException
;
35 import org
.osgi
.framework
.ServiceReference
;
36 import org
.osgi
.framework
.ServiceRegistration
;
37 import org
.osgi
.service
.useradmin
.Authorization
;
39 /** Default CMS session implementation. */
40 public class CmsSessionImpl
implements CmsSession
, Serializable
{
41 private static final long serialVersionUID
= 1867719354246307225L;
42 private final static BundleContext bc
= FrameworkUtil
.getBundle(CmsSessionImpl
.class).getBundleContext();
43 private final static CmsLog log
= CmsLog
.getLog(CmsSessionImpl
.class);
45 // private final Subject initialSubject;
46 private transient AccessControlContext accessControlContext
;
47 private final UUID uuid
;
48 private final String localSessionId
;
49 private Authorization authorization
;
50 private final LdapName userDn
;
51 private final boolean anonymous
;
53 private final ZonedDateTime creationTime
;
54 private ZonedDateTime end
;
55 private final Locale locale
;
57 private ServiceRegistration
<CmsSession
> serviceRegistration
;
59 private Map
<String
, Object
> views
= new HashMap
<>();
61 private List
<Consumer
<CmsSession
>> onCloseCallbacks
= Collections
.synchronizedList(new ArrayList
<>());
63 public CmsSessionImpl(Subject initialSubject
, Authorization authorization
, Locale locale
, String localSessionId
) {
64 this.creationTime
= ZonedDateTime
.now();
66 this.accessControlContext
= Subject
.doAs(initialSubject
, new PrivilegedAction
<AccessControlContext
>() {
69 public AccessControlContext
run() {
70 return AccessController
.getContext();
74 // this.initialSubject = initialSubject;
75 this.localSessionId
= localSessionId
;
76 this.authorization
= authorization
;
77 if (authorization
.getName() != null)
79 this.userDn
= new LdapName(authorization
.getName());
80 this.anonymous
= false;
81 } catch (InvalidNameException e
) {
82 throw new IllegalArgumentException("Invalid user name " + authorization
.getName(), e
);
85 this.userDn
= NodeSecurityUtils
.ROLE_ANONYMOUS_NAME
;
86 this.anonymous
= true;
88 this.uuid
= UUID
.randomUUID();
89 // register as service
90 Hashtable
<String
, String
> props
= new Hashtable
<>();
91 props
.put(CmsSession
.USER_DN
, userDn
.toString());
92 props
.put(CmsSession
.SESSION_UUID
, uuid
.toString());
93 props
.put(CmsSession
.SESSION_LOCAL_ID
, localSessionId
);
94 serviceRegistration
= bc
.registerService(CmsSession
.class, this, props
);
98 end
= ZonedDateTime
.now();
99 serviceRegistration
.unregister();
101 for (Consumer
<CmsSession
> onClose
: onCloseCallbacks
) {
102 onClose
.accept(this);
108 lc
= new LoginContext(CmsAuth
.LOGIN_CONTEXT_ANONYMOUS
, getSubject());
110 lc
= new LoginContext(CmsAuth
.LOGIN_CONTEXT_USER
, getSubject());
113 } catch (LoginException e
) {
114 log
.warn("Could not logout " + getSubject() + ": " + e
);
116 accessControlContext
= null;
118 log
.debug("Closed " + this);
122 public void addOnCloseCallback(Consumer
<CmsSession
> onClose
) {
123 onCloseCallbacks
.add(onClose
);
126 public Subject
getSubject() {
127 return Subject
.getSubject(accessControlContext
);
130 public Set
<SecretKey
> getSecretKeys() {
132 return getSubject().getPrivateCredentials(SecretKey
.class);
136 public boolean isValid() {
140 private void checkValid() {
142 throw new IllegalStateException("CMS session " + uuid
+ " is not valid since " + end
);
145 final protected boolean isClosed() {
146 return getEnd() != null;
149 public Authorization
getAuthorization() {
151 return authorization
;
155 public String
getDisplayName() {
156 return authorization
.toString();
160 public UUID
getUuid() {
165 public LdapName
getUserDn() {
170 public String
getUserRole() {
171 return new X500Principal(authorization
.getName()).getName();
175 public String
getLocalId() {
176 return localSessionId
;
180 public boolean isAnonymous() {
185 public Locale
getLocale() {
190 public ZonedDateTime
getCreationTime() {
195 public ZonedDateTime
getEnd() {
200 public void registerView(String uid
, Object view
) {
202 if (views
.containsKey(uid
))
203 throw new IllegalArgumentException("View " + uid
+ " is already registered.");
204 views
.put(uid
, view
);
207 public String
toString() {
208 return "CMS Session " + userDn
+ " local=" + localSessionId
+ ", uuid=" + uuid
;
211 public static CmsSessionImpl
getByLocalId(String localId
) {
212 Collection
<ServiceReference
<CmsSession
>> sr
;
214 sr
= bc
.getServiceReferences(CmsSession
.class, "(" + CmsSession
.SESSION_LOCAL_ID
+ "=" + localId
+ ")");
215 } catch (InvalidSyntaxException e
) {
216 throw new IllegalArgumentException("Cannot get CMS session for id " + localId
, e
);
218 ServiceReference
<CmsSession
> cmsSessionRef
;
219 if (sr
.size() == 1) {
220 cmsSessionRef
= sr
.iterator().next();
221 return (CmsSessionImpl
) bc
.getService(cmsSessionRef
);
222 } else if (sr
.size() == 0) {
225 throw new IllegalStateException(sr
.size() + " CMS sessions registered for " + localId
);
229 public static CmsSessionImpl
getByUuid(Object uuid
) {
230 Collection
<ServiceReference
<CmsSession
>> sr
;
232 sr
= bc
.getServiceReferences(CmsSession
.class, "(" + CmsSession
.SESSION_UUID
+ "=" + uuid
+ ")");
233 } catch (InvalidSyntaxException e
) {
234 throw new IllegalArgumentException("Cannot get CMS session for uuid " + uuid
, e
);
236 ServiceReference
<CmsSession
> cmsSessionRef
;
237 if (sr
.size() == 1) {
238 cmsSessionRef
= sr
.iterator().next();
239 return (CmsSessionImpl
) bc
.getService(cmsSessionRef
);
240 } else if (sr
.size() == 0) {
243 throw new IllegalStateException(sr
.size() + " CMS sessions registered for " + uuid
);
247 public static void closeInvalidSessions() {
248 Collection
<ServiceReference
<CmsSession
>> srs
;
250 srs
= bc
.getServiceReferences(CmsSession
.class, null);
251 for (ServiceReference
<CmsSession
> sr
: srs
) {
252 CmsSession cmsSession
= bc
.getService(sr
);
253 if (!cmsSession
.isValid()) {
254 ((CmsSessionImpl
) cmsSession
).close();
255 if (log
.isDebugEnabled())
256 log
.debug("Closed expired CMS session " + cmsSession
);
259 } catch (InvalidSyntaxException e
) {
260 throw new IllegalArgumentException("Cannot get CMS sessions", e
);