2 * Copyright (C) 2007-2012 Argeo GmbH
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package org
.argeo
.security
.jackrabbit
;
18 import java
.security
.Principal
;
19 import java
.util
.HashSet
;
20 import java
.util
.Properties
;
23 import javax
.jcr
.Credentials
;
24 import javax
.jcr
.Repository
;
25 import javax
.jcr
.RepositoryException
;
26 import javax
.jcr
.Session
;
27 import javax
.security
.auth
.Subject
;
28 import javax
.security
.auth
.callback
.CallbackHandler
;
29 import javax
.security
.auth
.x500
.X500Principal
;
31 import org
.apache
.commons
.logging
.Log
;
32 import org
.apache
.commons
.logging
.LogFactory
;
33 import org
.apache
.jackrabbit
.api
.security
.user
.UserManager
;
34 import org
.apache
.jackrabbit
.core
.DefaultSecurityManager
;
35 import org
.apache
.jackrabbit
.core
.security
.AMContext
;
36 import org
.apache
.jackrabbit
.core
.security
.AccessManager
;
37 import org
.apache
.jackrabbit
.core
.security
.SecurityConstants
;
38 import org
.apache
.jackrabbit
.core
.security
.SystemPrincipal
;
39 import org
.apache
.jackrabbit
.core
.security
.authentication
.AuthContext
;
40 import org
.apache
.jackrabbit
.core
.security
.authentication
.CallbackHandlerImpl
;
41 import org
.apache
.jackrabbit
.core
.security
.authorization
.WorkspaceAccessManager
;
42 import org
.apache
.jackrabbit
.core
.security
.principal
.AdminPrincipal
;
43 import org
.apache
.jackrabbit
.core
.security
.principal
.PrincipalProvider
;
44 import org
.argeo
.api
.NodeConstants
;
45 import org
.argeo
.api
.security
.AnonymousPrincipal
;
46 import org
.argeo
.api
.security
.DataAdminPrincipal
;
47 import org
.argeo
.cms
.auth
.CmsSession
;
48 import org
.osgi
.framework
.BundleContext
;
49 import org
.osgi
.framework
.FrameworkUtil
;
51 /** Customises Jackrabbit security. */
52 public class ArgeoSecurityManager
extends DefaultSecurityManager
{
53 private final static Log log
= LogFactory
.getLog(ArgeoSecurityManager
.class);
55 private BundleContext cmsBundleContext
= null;
57 public ArgeoSecurityManager() {
58 if (FrameworkUtil
.getBundle(CmsSession
.class) != null) {
59 cmsBundleContext
= FrameworkUtil
.getBundle(CmsSession
.class).getBundleContext();
63 public AuthContext
getAuthContext(Credentials creds
, Subject subject
, String workspaceName
)
64 throws RepositoryException
{
67 CallbackHandler cbHandler
= new CallbackHandlerImpl(creds
, getSystemSession(), getPrincipalProviderRegistry(),
68 adminId
, anonymousId
);
69 String appName
= "Jackrabbit";
70 return new ArgeoAuthContext(appName
, subject
, cbHandler
);
74 public AccessManager
getAccessManager(Session session
, AMContext amContext
) throws RepositoryException
{
75 synchronized (getSystemSession()) {
76 return super.getAccessManager(session
, amContext
);
81 public UserManager
getUserManager(Session session
) throws RepositoryException
{
82 synchronized (getSystemSession()) {
83 return super.getUserManager(session
);
88 protected PrincipalProvider
createDefaultPrincipalProvider(Properties
[] moduleConfig
) throws RepositoryException
{
89 return super.createDefaultPrincipalProvider(moduleConfig
);
92 /** Called once when the session is created */
94 public String
getUserID(Subject subject
, String workspaceName
) throws RepositoryException
{
95 boolean isAnonymous
= !subject
.getPrincipals(AnonymousPrincipal
.class).isEmpty();
96 boolean isDataAdmin
= !subject
.getPrincipals(DataAdminPrincipal
.class).isEmpty();
97 boolean isJackrabbitSystem
= !subject
.getPrincipals(SystemPrincipal
.class).isEmpty();
98 Set
<X500Principal
> userPrincipal
= subject
.getPrincipals(X500Principal
.class);
99 boolean isRegularUser
= !userPrincipal
.isEmpty();
100 CmsSession cmsSession
= null;
101 if (cmsBundleContext
!= null) {
102 cmsSession
= CmsSession
.getCmsSession(cmsBundleContext
, subject
);
103 if (log
.isTraceEnabled())
104 log
.trace("Opening JCR session for CMS session " + cmsSession
);
108 if (isDataAdmin
|| isJackrabbitSystem
|| isRegularUser
)
109 throw new IllegalStateException("Inconsistent " + subject
);
111 return NodeConstants
.ROLE_ANONYMOUS
;
112 } else if (isRegularUser
) {// must be before DataAdmin
113 if (isAnonymous
|| isJackrabbitSystem
)
114 throw new IllegalStateException("Inconsistent " + subject
);
116 if (userPrincipal
.size() > 1) {
117 StringBuilder buf
= new StringBuilder();
118 for (X500Principal principal
: userPrincipal
)
119 buf
.append(' ').append('\"').append(principal
).append('\"');
120 throw new RuntimeException("Multiple user principals:" + buf
);
122 return userPrincipal
.iterator().next().getName();
124 } else if (isDataAdmin
) {
125 if (isAnonymous
|| isJackrabbitSystem
|| isRegularUser
)
126 throw new IllegalStateException("Inconsistent " + subject
);
128 assert !subject
.getPrincipals(AdminPrincipal
.class).isEmpty();
129 return NodeConstants
.ROLE_DATA_ADMIN
;
131 } else if (isJackrabbitSystem
) {
132 if (isAnonymous
|| isDataAdmin
|| isRegularUser
)
133 throw new IllegalStateException("Inconsistent " + subject
);
135 return super.getUserID(subject
, workspaceName
);
137 throw new IllegalStateException("Unrecognized subject type: " + subject
);
142 protected WorkspaceAccessManager
createDefaultWorkspaceAccessManager() {
143 WorkspaceAccessManager wam
= super.createDefaultWorkspaceAccessManager();
144 ArgeoWorkspaceAccessManagerImpl workspaceAccessManager
= new ArgeoWorkspaceAccessManagerImpl(wam
);
145 if (log
.isTraceEnabled())
146 log
.trace("Created workspace access manager");
147 return workspaceAccessManager
;
150 private class ArgeoWorkspaceAccessManagerImpl
implements SecurityConstants
, WorkspaceAccessManager
{
151 private final WorkspaceAccessManager wam
;
153 public ArgeoWorkspaceAccessManagerImpl(WorkspaceAccessManager wam
) {
158 public void init(Session systemSession
) throws RepositoryException
{
159 wam
.init(systemSession
);
160 Repository repository
= systemSession
.getRepository();
161 if (log
.isTraceEnabled())
162 log
.trace("Initialised workspace access manager on repository " + repository
163 + ", systemSession workspace: " + systemSession
.getWorkspace().getName());
166 public void close() throws RepositoryException
{
169 public boolean grants(Set
<Principal
> principals
, String workspaceName
) throws RepositoryException
{
170 // TODO: implements finer access to workspaces
171 if (log
.isTraceEnabled())
172 log
.trace("Grants " + new HashSet
<>(principals
) + " access to workspace '" + workspaceName
+ "'");
174 // return wam.grants(principals, workspaceName);