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