]> git.argeo.org Git - lgpl/argeo-commons.git/blob - CmsSessionImpl.java
164d319f197ae92074b2c5965233deb6f7c1be5c
[lgpl/argeo-commons.git] / 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.Collections;
10 import java.util.HashMap;
11 import java.util.List;
12 import java.util.Locale;
13 import java.util.Map;
14 import java.util.Objects;
15 import java.util.Set;
16 import java.util.UUID;
17 import java.util.function.Consumer;
18
19 import javax.crypto.SecretKey;
20 import javax.naming.InvalidNameException;
21 import javax.naming.ldap.LdapName;
22 import javax.security.auth.Subject;
23 import javax.security.auth.login.LoginContext;
24 import javax.security.auth.login.LoginException;
25 import javax.security.auth.x500.X500Principal;
26
27 import org.argeo.api.cms.CmsAuth;
28 import org.argeo.api.cms.CmsLog;
29 import org.argeo.api.cms.CmsSession;
30 import org.argeo.cms.internal.runtime.CmsContextImpl;
31 import org.argeo.cms.security.NodeSecurityUtils;
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 private List<Consumer<CmsSession>> onCloseCallbacks = Collections.synchronizedList(new ArrayList<>());
58
59 public CmsSessionImpl(UUID uuid, Subject initialSubject, Authorization authorization, Locale locale,
60 String localSessionId) {
61 Objects.requireNonNull(uuid);
62
63 this.creationTime = ZonedDateTime.now();
64 this.locale = locale;
65 this.accessControlContext = Subject.doAs(initialSubject, new PrivilegedAction<AccessControlContext>() {
66
67 @Override
68 public AccessControlContext run() {
69 return AccessController.getContext();
70 }
71
72 });
73 // this.initialSubject = initialSubject;
74 this.localSessionId = localSessionId;
75 this.authorization = authorization;
76 if (authorization.getName() != null)
77 try {
78 this.userDn = new LdapName(authorization.getName());
79 this.anonymous = false;
80 } catch (InvalidNameException e) {
81 throw new IllegalArgumentException("Invalid user name " + authorization.getName(), e);
82 }
83 else {
84 this.userDn = NodeSecurityUtils.ROLE_ANONYMOUS_NAME;
85 this.anonymous = true;
86 }
87 this.uuid = uuid;
88 }
89
90 public void close() {
91 end = ZonedDateTime.now();
92 CmsContextImpl.getCmsContext().unregisterCmsSession(this);
93 // serviceRegistration.unregister();
94
95 for (Consumer<CmsSession> onClose : onCloseCallbacks) {
96 onClose.accept(this);
97 }
98
99 try {
100 LoginContext lc;
101 if (isAnonymous()) {
102 lc = new LoginContext(CmsAuth.LOGIN_CONTEXT_ANONYMOUS, getSubject());
103 } else {
104 lc = new LoginContext(CmsAuth.LOGIN_CONTEXT_USER, getSubject());
105 }
106 lc.logout();
107 } catch (LoginException e) {
108 log.warn("Could not logout " + getSubject() + ": " + e);
109 } finally {
110 accessControlContext = null;
111 }
112 log.debug("Closed " + this);
113 }
114
115 @Override
116 public void addOnCloseCallback(Consumer<CmsSession> onClose) {
117 onCloseCallbacks.add(onClose);
118 }
119
120 public Subject getSubject() {
121 return Subject.getSubject(accessControlContext);
122 }
123
124 public Set<SecretKey> getSecretKeys() {
125 checkValid();
126 return getSubject().getPrivateCredentials(SecretKey.class);
127 }
128
129 @Override
130 public boolean isValid() {
131 return !isClosed();
132 }
133
134 private void checkValid() {
135 if (!isValid())
136 throw new IllegalStateException("CMS session " + uuid + " is not valid since " + end);
137 }
138
139 final protected boolean isClosed() {
140 return getEnd() != null;
141 }
142
143 public Authorization getAuthorization() {
144 checkValid();
145 return authorization;
146 }
147
148 @Override
149 public String getDisplayName() {
150 return authorization.toString();
151 }
152
153 @Override
154 public UUID getUuid() {
155 return uuid;
156 }
157
158 @Override
159 public LdapName getUserDn() {
160 return userDn;
161 }
162
163 @Override
164 public String getUserRole() {
165 return new X500Principal(authorization.getName()).getName();
166 }
167
168 @Override
169 public String getLocalId() {
170 return localSessionId;
171 }
172
173 @Override
174 public boolean isAnonymous() {
175 return anonymous;
176 }
177
178 @Override
179 public Locale getLocale() {
180 return locale;
181 }
182
183 @Override
184 public ZonedDateTime getCreationTime() {
185 return creationTime;
186 }
187
188 @Override
189 public ZonedDateTime getEnd() {
190 return end;
191 }
192
193 @Override
194 public void registerView(String uid, Object view) {
195 checkValid();
196 if (views.containsKey(uid))
197 throw new IllegalArgumentException("View " + uid + " is already registered.");
198 views.put(uid, view);
199 }
200
201 public String toString() {
202 return "CMS Session " + userDn + " localId=" + localSessionId + ", uuid=" + uuid;
203 }
204 }