]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/internal/auth/CmsSessionImpl.java
Fix automated Kerberos config
[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 // FIXME make it more robust
79 if (workspace == null)
80 workspace = "main";
81 String path = cn + '/' + workspace;
82 if (dataSessionsInUse.contains(path)) {
83 try {
84 wait(1000);
85 if (dataSessionsInUse.contains(path)) {
86 Session session = login(repository, workspace);
87 additionalDataSessions.add(session);
88 if (log.isTraceEnabled())
89 log.trace("Additional data session " + path + " for " + userDn);
90 return session;
91 }
92 } catch (InterruptedException e) {
93 // silent
94 }
95 }
96
97 Session session = null;
98 if (dataSessions.containsKey(path)) {
99 session = dataSessions.get(path);
100 } else {
101 session = login(repository, workspace);
102 dataSessions.put(path, session);
103 if (log.isTraceEnabled())
104 log.trace("New data session " + path + " for " + userDn);
105 }
106 dataSessionsInUse.add(path);
107 return session;
108 }
109
110 private Session login(Repository repository, String workspace) {
111 try {
112 return Subject.doAs(initialSubject, new PrivilegedExceptionAction<Session>() {
113 @Override
114 public Session run() throws Exception {
115 return repository.login(workspace);
116 }
117 });
118 } catch (Exception e) {
119 throw new CmsException("Cannot log in " + userDn + " to JCR", e);
120 }
121 }
122
123 @Override
124 public synchronized void releaseDataSession(String cn, Session session) {
125 if (additionalDataSessions.contains(session)) {
126 JcrUtils.logoutQuietly(session);
127 additionalDataSessions.remove(session);
128 return;
129 }
130 String path = cn + '/' + session.getWorkspace().getName();
131 if (!dataSessionsInUse.contains(path))
132 log.warn("Data session " + path + " was not in use for " + userDn);
133 dataSessionsInUse.remove(path);
134 Session registeredSession = dataSessions.get(path);
135 if (session != registeredSession)
136 log.warn("Data session " + path + " not consistent for " + userDn);
137 notifyAll();
138 }
139
140 @Override
141 public Authorization getAuthorization() {
142 return authorization;
143 }
144
145 @Override
146 public UUID getUuid() {
147 return uuid;
148 }
149
150 public Subject getInitialSubject() {
151 return initialSubject;
152 }
153
154 public String getLocalSessionId() {
155 return localSessionId;
156 }
157
158 public ServiceRegistration<CmsSession> getServiceRegistration() {
159 return serviceRegistration;
160 }
161
162 @Override
163 public LdapName getUserDn() {
164 return userDn;
165 }
166
167 @Override
168 public String getLocalId() {
169 return localSessionId;
170 }
171
172 public String toString() {
173 return "CMS Session local=" + localSessionId + ", uuid=" + uuid;
174 }
175
176 public static CmsSession getByLocalId(String localId) {
177 Collection<ServiceReference<CmsSession>> sr;
178 try {
179 sr = bc.getServiceReferences(CmsSession.class, "(" + CmsSession.SESSION_LOCAL_ID + "=" + localId + ")");
180 } catch (InvalidSyntaxException e) {
181 throw new CmsException("Cannot get CMS session for id " + localId, e);
182 }
183 ServiceReference<CmsSession> cmsSessionRef;
184 if (sr.size() == 1) {
185 cmsSessionRef = sr.iterator().next();
186 return bc.getService(cmsSessionRef);
187 } else if (sr.size() == 0) {
188 return null;
189 } else
190 throw new CmsException(sr.size() + " CMS sessions registered for " + localId);
191
192 }
193
194 public static CmsSession getByUuid(String uuid) {
195 Collection<ServiceReference<CmsSession>> sr;
196 try {
197 sr = bc.getServiceReferences(CmsSession.class, "(" + CmsSession.SESSION_UUID + "=" + uuid + ")");
198 } catch (InvalidSyntaxException e) {
199 throw new CmsException("Cannot get CMS session for uuid " + uuid, e);
200 }
201 ServiceReference<CmsSession> cmsSessionRef;
202 if (sr.size() == 1) {
203 cmsSessionRef = sr.iterator().next();
204 return bc.getService(cmsSessionRef);
205 } else if (sr.size() == 0) {
206 return null;
207 } else
208 throw new CmsException(sr.size() + " CMS sessions registered for " + uuid);
209
210 }
211 }