View Javadoc

1   /**
2    * This file Copyright (c) 2003-2010 Magnolia International
3    * Ltd.  (http://www.magnolia-cms.com). All rights reserved.
4    *
5    *
6    * This file is dual-licensed under both the Magnolia
7    * Network Agreement and the GNU General Public License.
8    * You may elect to use one or the other of these licenses.
9    *
10   * This file is distributed in the hope that it will be
11   * useful, but AS-IS and WITHOUT ANY WARRANTY; without even the
12   * implied warranty of MERCHANTABILITY or FITNESS FOR A
13   * PARTICULAR PURPOSE, TITLE, or NONINFRINGEMENT.
14   * Redistribution, except as permitted by whichever of the GPL
15   * or MNA you select, is prohibited.
16   *
17   * 1. For the GPL license (GPL), you can redistribute and/or
18   * modify this file under the terms of the GNU General
19   * Public License, Version 3, as published by the Free Software
20   * Foundation.  You should have received a copy of the GNU
21   * General Public License, Version 3 along with this program;
22   * if not, write to the Free Software Foundation, Inc., 51
23   * Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
24   *
25   * 2. For the Magnolia Network Agreement (MNA), this file
26   * and the accompanying materials are made available under the
27   * terms of the MNA which accompanies this distribution, and
28   * is available at http://www.magnolia-cms.com/mna.html
29   *
30   * Any modifications to this file must keep this entire header
31   * intact.
32   *
33   */
34  package info.magnolia.jaas.sp.jcr;
35  
36  import info.magnolia.cms.beans.config.ContentRepository;
37  import info.magnolia.cms.core.Content;
38  import info.magnolia.cms.core.HierarchyManager;
39  import info.magnolia.cms.core.ItemType;
40  import info.magnolia.cms.security.MgnlUser;
41  import info.magnolia.cms.security.Permission;
42  import info.magnolia.cms.security.PermissionImpl;
43  import info.magnolia.cms.security.SecuritySupport;
44  import info.magnolia.cms.security.User;
45  import info.magnolia.cms.security.auth.ACL;
46  import info.magnolia.cms.security.auth.GroupList;
47  import info.magnolia.cms.security.auth.PrincipalCollection;
48  import info.magnolia.cms.security.auth.RoleList;
49  import info.magnolia.cms.security.auth.callback.CredentialsCallbackHandler;
50  import info.magnolia.cms.util.SimpleUrlPattern;
51  import info.magnolia.cms.util.UrlPattern;
52  import info.magnolia.context.MgnlContext;
53  import info.magnolia.jaas.principal.ACLImpl;
54  import info.magnolia.jaas.principal.GroupListImpl;
55  import info.magnolia.jaas.principal.PrincipalCollectionImpl;
56  import info.magnolia.jaas.principal.RoleListImpl;
57  import info.magnolia.jaas.sp.AbstractLoginModule;
58  
59  import java.security.Principal;
60  import java.util.Iterator;
61  
62  import javax.jcr.PathNotFoundException;
63  import javax.jcr.RepositoryException;
64  import javax.security.auth.login.LoginException;
65  
66  import org.apache.commons.lang.ArrayUtils;
67  import org.apache.commons.lang.StringUtils;
68  import org.slf4j.Logger;
69  import org.slf4j.LoggerFactory;
70  
71  
72  /**
73   * This is a default login module for magnolia, it uses initialized repository as defined by the provider interface
74   * @author Sameer Charles
75   * @version $Id: JCRAuthorizationModule.java 34718 2010-05-28 10:54:28Z had $
76   */
77  public class JCRAuthorizationModule extends AbstractLoginModule {
78  
79      public void validateUser() throws LoginException {
80      }
81  
82      /**
83       * Logger
84       */
85      private static final Logger log = LoggerFactory.getLogger(JCRAuthorizationModule.class);
86  
87      // do nothing here, we are only responsible for authorization, not authentication!
88      public boolean login() throws LoginException
89      {
90          this.success = true;
91          this.setSharedStatus(STATUS_SUCCEEDED);
92          return this.success;
93      }
94  
95      /**
96       * set access control list from the user, roles and groups
97       */
98      public void setACL() {
99          String[] roles = (String[]) getRoleNames().toArray(new String[getRoleNames().size()]);
100         String[] groups = (String[]) getGroupNames().toArray(new String[getGroupNames().size()]);
101 
102         if (log.isDebugEnabled()) {
103             log.debug("Roles: {}", ArrayUtils.toString(roles));
104             log.debug("Groups: {}", ArrayUtils.toString(groups));
105         }
106 
107         addRoles(roles);
108         addGroups(groups);
109 
110         PrincipalCollection principalList = new PrincipalCollectionImpl();
111         setACLForRoles(roles, principalList);
112         setACLForGroups(groups, principalList);
113         User user = null;
114         if (callbackHandler instanceof CredentialsCallbackHandler) {
115             user = ((CredentialsCallbackHandler) callbackHandler).getUser();
116         }
117         // not all jaas modules will support magnolia users
118         if(user == null){
119             user = SecuritySupport.Factory.getInstance().getUserManager().getUser(subject);
120         }
121 
122         if (user instanceof MgnlUser) {
123             setACL(((MgnlUser)user).getUserNode(), principalList);
124         }
125 
126          if (log.isDebugEnabled()) {
127             for (Iterator iterator = ((PrincipalCollectionImpl) principalList).iterator(); iterator.hasNext();) {
128                 Principal principal = (Principal) iterator.next();
129                 log.debug("ACL: {}", principal);
130             }
131 
132         }
133 
134         // set principal list, a set of info.magnolia.jaas.principal.ACL
135         this.subject.getPrincipals().add(principalList);
136     }
137 
138     // do nothing here, we are only responsible for adding ACL passed on via shared state
139     public void setEntity() {}
140 
141     /**
142      * Set the list of groups, info.magnolia.jaas.principal.GroupList.
143      * @param groups array of group names
144      */
145     protected void addGroups(String[] groups) {
146         GroupList groupList = new GroupListImpl();
147         for (Iterator iterator = getGroupNames().iterator(); iterator.hasNext();) {
148             String group = (String) iterator.next();
149             groupList.add(group);
150         }
151         this.subject.getPrincipals().add(groupList);
152     }
153 
154     /**
155      * Set the list of roles, info.magnolia.jaas.principal.RoleList.
156      * @param roles array of role names
157      */
158     protected void addRoles(String[] roles) {
159         RoleList roleList = new RoleListImpl();
160         for (Iterator iterator = getRoleNames().iterator(); iterator.hasNext();) {
161             String role = (String) iterator.next();
162             roleList.add(role);
163         }
164         this.subject.getPrincipals().add(roleList);
165     }
166 
167     /**
168      * Looks for rolee configured in magnolia repository with the given name, and configures ACLs for it.
169      * @param roles array of role names.
170      * @param principalList PrincipalCollection
171      */
172     protected void setACLForRoles(String[] roles, PrincipalCollection principalList) {
173 
174         HierarchyManager hm = MgnlContext.getSystemContext().getHierarchyManager(ContentRepository.USER_ROLES);
175 
176         for (int j = 0; j < roles.length; j++) {
177             String role = roles[j];
178             try {
179                 setACL(hm.getContent(role), principalList);
180             }
181             catch (PathNotFoundException e) {
182                 log.info("Role {} not found", role);
183             }
184             catch (RepositoryException e) {
185                 log.warn("Error accessing {} role: {}", role, e.getMessage());
186             }
187         }
188     }
189 
190     /**
191      * Looks for groups configured in magnolia repository with the given name, and configures ACLs for it.
192      * @param groups array of group names.
193      * @param principalList PrincipalCollection
194      */
195     protected void setACLForGroups(String[] groups, PrincipalCollection principalList) {
196         HierarchyManager hm = MgnlContext.getSystemContext().getHierarchyManager(ContentRepository.USER_GROUPS);
197 
198         for (int j = 0; j < groups.length; j++) {
199             String group = groups[j];
200             try {
201                 setACL(hm.getContent(group), principalList);
202             }
203             catch (PathNotFoundException e) {
204                 log.info("Group {} not found", group);
205             }
206             catch (RepositoryException e) {
207                 log.warn("Error accessing {} group: {}", group, e.getMessage());
208             }
209         }
210     }
211 
212     /**
213      * set access control list from a list of roles under the provided content object
214      * @param node under which roles and ACL are defined
215      */
216     private void setACL(Content node, PrincipalCollection principalList) {
217         Iterator it = node.getChildren(ItemType.CONTENTNODE.getSystemName(), "acl*").iterator();
218         while (it.hasNext()) {
219             Content aclEntry = (Content) it.next();
220             String name = StringUtils.substringAfter(aclEntry.getName(), "acl_");
221             ACL acl;
222             String repositoryName;
223             String workspaceName;
224             if (!StringUtils.contains(name, "_")) {
225                 repositoryName = name;
226                 workspaceName = ContentRepository.getDefaultWorkspace(name);
227                 name += ("_" + workspaceName); // default workspace must be added to the name
228             }
229             else {
230                 String[] tokens = StringUtils.split(name, "_");
231                 repositoryName = tokens[0];
232                 workspaceName = tokens[1];
233             }
234             // get the existing acl object if created before with some
235             // other role
236             if (!principalList.contains(name)) {
237                 acl = new ACLImpl();
238                 principalList.add(acl);
239             }
240             else {
241                 acl = (ACL) principalList.get(name);
242             }
243             acl.setName(name);
244             acl.setRepository(repositoryName);
245             acl.setWorkspace(workspaceName);
246 
247             // add acl
248             Iterator permissionIterator = aclEntry.getChildren().iterator();
249             while (permissionIterator.hasNext()) {
250                 Content map = (Content) permissionIterator.next();
251                 String path = map.getNodeData("path").getString();
252                 UrlPattern p = new SimpleUrlPattern(path);
253                 Permission permission = new PermissionImpl();
254                 permission.setPattern(p);
255                 permission.setPermissions(map.getNodeData("permissions").getLong());
256                 acl.addPermission(permission);
257             }
258         }
259     }
260 
261     /**
262      * {@inheritDoc}
263      */
264     public boolean release() {
265         return true;
266     }
267 
268 }