]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/internal/auth/CmsSessionImpl.java
Change files path
[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.security.PrivilegedExceptionAction;
4 import java.util.Collection;
5 import java.util.HashMap;
6 import java.util.HashSet;
7 import java.util.Hashtable;
8 import java.util.LinkedHashSet;
9 import java.util.Map;
10 import java.util.Set;
11 import java.util.UUID;
12
13 import javax.jcr.Repository;
14 import javax.jcr.Session;
15 import javax.naming.InvalidNameException;
16 import javax.naming.ldap.LdapName;
17 import javax.security.auth.Subject;
18
19 import org.apache.commons.logging.Log;
20 import org.apache.commons.logging.LogFactory;
21 import org.argeo.cms.CmsException;
22 import org.argeo.cms.auth.CmsSession;
23 import org.argeo.jcr.JcrUtils;
24 import org.osgi.framework.BundleContext;
25 import org.osgi.framework.FrameworkUtil;
26 import org.osgi.framework.InvalidSyntaxException;
27 import org.osgi.framework.ServiceReference;
28 import org.osgi.framework.ServiceRegistration;
29 import org.osgi.service.useradmin.Authorization;
30
31 public class CmsSessionImpl implements CmsSession {
32 private final static BundleContext bc = FrameworkUtil.getBundle(CmsSessionImpl.class).getBundleContext();
33 private final static Log log = LogFactory.getLog(CmsSessionImpl.class);
34
35 private final Subject initialSubject;
36 private final UUID uuid;
37 private final String localSessionId;
38 private final Authorization authorization;
39 private final LdapName userDn;
40
41 private ServiceRegistration<CmsSession> serviceRegistration;
42
43 private Map<String, Session> dataSessions = new HashMap<>();
44 private Set<String> dataSessionsInUse = new HashSet<>();
45 private LinkedHashSet<Session> additionalDataSessions = new LinkedHashSet<>();
46
47 public CmsSessionImpl(Subject initialSubject, Authorization authorization, String localSessionId) {
48 this.initialSubject = initialSubject;
49 this.localSessionId = localSessionId;
50 this.authorization = authorization;
51 try {
52 this.userDn = new LdapName(authorization.getName());
53 } catch (InvalidNameException e) {
54 throw new CmsException("Invalid user name " + authorization.getName(), e);
55 }
56 this.uuid = UUID.randomUUID();
57 // register as service
58 Hashtable<String, String> props = new Hashtable<>();
59 props.put(CmsSession.USER_DN, authorization.getName());
60 props.put(CmsSession.SESSION_UUID, uuid.toString());
61 props.put(CmsSession.SESSION_LOCAL_ID, localSessionId);
62 serviceRegistration = bc.registerService(CmsSession.class, this, props);
63 }
64
65 public synchronized void cleanUp() {
66 serviceRegistration.unregister();
67
68 // TODO check data session in use ?
69 for (String path : dataSessions.keySet())
70 JcrUtils.logoutQuietly(dataSessions.get(path));
71 for (Session session : additionalDataSessions)
72 JcrUtils.logoutQuietly(session);
73 notifyAll();
74 }
75
76 @Override
77 public synchronized Session getDataSession(String cn, String workspace, Repository repository) {
78 String path = cn + '/' + workspace;
79 if (dataSessionsInUse.contains(path)) {
80 try {
81 wait(1000);
82 if (dataSessionsInUse.contains(path)) {
83 Session session = login(repository, workspace);
84 additionalDataSessions.add(session);
85 if (log.isTraceEnabled())
86 log.trace("Additional data session " + path + " for " + userDn);
87 return session;
88 }
89 } catch (InterruptedException e) {
90 // silent
91 }
92 }
93
94 Session session = null;
95 if (dataSessions.containsKey(path)) {
96 session = dataSessions.get(path);
97 } else {
98 session = login(repository, workspace);
99 dataSessions.put(path, session);
100 if (log.isTraceEnabled())
101 log.trace("New data session " + path + " for " + userDn);
102 }
103 dataSessionsInUse.add(path);
104 return session;
105 }
106
107 private Session login(Repository repository, String workspace) {
108 try {
109 return Subject.doAs(initialSubject, new PrivilegedExceptionAction<Session>() {
110 @Override
111 public Session run() throws Exception {
112 return repository.login(workspace);
113 }
114 });
115 } catch (Exception e) {
116 throw new CmsException("Cannot log in " + userDn + " to JCR", e);
117 }
118 }
119
120 @Override
121 public synchronized void releaseDataSession(String cn, Session session) {
122 if (additionalDataSessions.contains(session)) {
123 JcrUtils.logoutQuietly(session);
124 additionalDataSessions.remove(session);
125 return;
126 }
127 String path = cn + '/' + session.getWorkspace().getName();
128 if (!dataSessionsInUse.contains(path))
129 log.warn("Data session " + path + " was not in use for " + userDn);
130 dataSessionsInUse.remove(path);
131 Session registeredSession = dataSessions.get(path);
132 if (session != registeredSession)
133 log.warn("Data session " + path + " not consistent for " + userDn);
134 notifyAll();
135 }
136
137 @Override
138 public Authorization getAuthorization() {
139 return authorization;
140 }
141
142 @Override
143 public UUID getUuid() {
144 return uuid;
145 }
146
147 public Subject getInitialSubject() {
148 return initialSubject;
149 }
150
151 public String getLocalSessionId() {
152 return localSessionId;
153 }
154
155 public ServiceRegistration<CmsSession> getServiceRegistration() {
156 return serviceRegistration;
157 }
158
159 @Override
160 public LdapName getUserDn() {
161 return userDn;
162 }
163
164 @Override
165 public String getLocalId() {
166 return localSessionId;
167 }
168
169 public String toString() {
170 return "CMS Session #" + localSessionId;
171 }
172
173 public static CmsSession getByLocalId(String localId) {
174 Collection<ServiceReference<CmsSession>> sr;
175 try {
176 sr = bc.getServiceReferences(CmsSession.class, "(" + CmsSession.SESSION_LOCAL_ID + "=" + localId + ")");
177 } catch (InvalidSyntaxException e) {
178 throw new CmsException("Cannot get CMS session for id " + localId, e);
179 }
180 ServiceReference<CmsSession> cmsSessionRef;
181 if (sr.size() == 1) {
182 cmsSessionRef = sr.iterator().next();
183 return bc.getService(cmsSessionRef);
184 } else if (sr.size() == 0) {
185 return null;
186 } else
187 throw new CmsException(sr.size() + " CMS sessions registered for " + localId);
188
189 }
190
191 public static CmsSession getByUuid(String uuid) {
192 Collection<ServiceReference<CmsSession>> sr;
193 try {
194 sr = bc.getServiceReferences(CmsSession.class, "(" + CmsSession.SESSION_UUID + "=" + uuid + ")");
195 } catch (InvalidSyntaxException e) {
196 throw new CmsException("Cannot get CMS session for uuid " + uuid, e);
197 }
198 ServiceReference<CmsSession> cmsSessionRef;
199 if (sr.size() == 1) {
200 cmsSessionRef = sr.iterator().next();
201 return bc.getService(cmsSessionRef);
202 } else if (sr.size() == 0) {
203 return null;
204 } else
205 throw new CmsException(sr.size() + " CMS sessions registered for " + uuid);
206
207 }
208 }