001: /*
002: * Copyright 2007 Pentaho Corporation. All rights reserved.
003: * This software was developed by Pentaho Corporation and is provided under the terms
004: * of the Mozilla Public License, Version 1.1, or any later version. You may not use
005: * this file except in compliance with the license. If you need a copy of the license,
006: * please go to http://www.mozilla.org/MPL/MPL-1.1.txt. The Original Code is the Pentaho
007: * BI Platform. The Initial Developer is Pentaho Corporation.
008: *
009: * Software distributed under the Mozilla Public License is distributed on an "AS IS"
010: * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. Please refer to
011: * the license for the specific language governing your rights and limitations.
012: */
013: package com.pentaho.security;
014:
015: import java.security.Principal;
016: import java.util.List;
017:
018: import org.acegisecurity.Authentication;
019: import org.acegisecurity.GrantedAuthority;
020: import org.acegisecurity.GrantedAuthorityImpl;
021: import org.acegisecurity.providers.UsernamePasswordAuthenticationToken;
022: import org.apache.commons.logging.Log;
023: import org.apache.commons.logging.LogFactory;
024: import org.pentaho.core.repository.ISolutionRepository;
025: import org.pentaho.core.session.IPentahoSession;
026: import org.pentaho.core.system.PentahoSystem;
027:
028: import com.pentaho.repository.dbbased.solution.RepositoryFile;
029: import com.pentaho.security.acls.IAclHolder;
030: import com.pentaho.security.acls.PentahoAclEntry;
031: import com.pentaho.security.acls.voter.IAclVoter;
032:
033: /**
034: * A utility class with several static methods that are used to
035: * either bind the <tt>Authentication</tt> to the <tt>IPentahoSession</tt>, retrieve
036: * the <tt>Authentication</tt> from the <tt>IPentahoSession</tt>, and other various helper
037: * functions.
038: * @author mbatchel
039: *
040: */
041:
042: public class SecurityUtils {
043:
044: private static final Log logger = LogFactory
045: .getLog(SecurityUtils.class);
046:
047: public static final String SESSION_PRINCIPAL = "SECURITY_PRINCIPAL"; //$NON-NLS-1$
048:
049: public static String DefaultAnonymousRole = PentahoSystem
050: .getSystemSetting(
051: "anonymous-authentication/anonymous-role", "Anonymous"); //$NON-NLS-1$ //$NON-NLS-2$
052:
053: public static String DefaultAnonymousUser = PentahoSystem
054: .getSystemSetting(
055: "anonymous-authentication/anonymous-user", "anonymous"); //$NON-NLS-1$ //$NON-NLS-2$
056:
057: /**
058: * Looks in the provided session to get the ACEGI Authentication object out.
059: * Optionally returns an "anonymous" Authentication if desired.
060: * @param session Users' IPentahoSession object
061: * @param allowAnonymous If true, will return an anonymous Authentication object.
062: * @return the Authentication object from the session
063: */
064: public static Authentication getAuthentication(
065: IPentahoSession session, boolean allowAnonymous) {
066: Principal principal = (Principal) session
067: .getAttribute(SESSION_PRINCIPAL);
068: if (logger.isDebugEnabled()) {
069: logger
070: .debug("principal from IPentahoSession: " + principal); //$NON-NLS-1$
071: if (null != principal) {
072: logger
073: .debug("principal class: " + principal.getClass().getName()); //$NON-NLS-1$
074: }
075: }
076: if (principal instanceof Authentication) {
077: if (logger.isDebugEnabled()) {
078: logger
079: .debug("principal is an instance of Authentication"); //$NON-NLS-1$
080: }
081: return (Authentication) principal;
082: } else if (principal != null) {
083: if (logger.isDebugEnabled()) {
084: logger
085: .debug("principal is not an instance of Authentication"); //$NON-NLS-1$
086: logger.debug("attempting role fetch with username"); //$NON-NLS-1$
087: }
088:
089: // OK - Not ACEGI somehow.
090: // However, since the principal interface doesn't specify the
091: // roles a user is in, we need to dispatch a call to the
092: // UserRoleListProvider to get that information from there.
093:
094: UserDetailsRoleListService roleListService = PentahoSystem
095: .getUserDetailsRoleListService();
096: List roles = roleListService.getRolesForUser(principal
097: .getName());
098: if (logger.isDebugEnabled()) {
099: logger
100: .debug("rolesForUser from roleListService:" + roles); //$NON-NLS-1$
101: }
102: if (!roles.isEmpty()) {
103: GrantedAuthority[] grantedAuthorities = new GrantedAuthority[roles
104: .size()];
105: for (int i = 0; i < roles.size(); i++) {
106: grantedAuthorities[i] = new GrantedAuthorityImpl(
107: (String) roles.get(i));
108: }
109:
110: Authentication auth = new UsernamePasswordAuthenticationToken(
111: principal.getName(), null, grantedAuthorities);
112:
113: return auth;
114: }
115: }
116: if (logger.isDebugEnabled()) {
117: logger
118: .debug("either principal is null or user has no roles"); //$NON-NLS-1$
119: }
120:
121: if (allowAnonymous) {
122: if (logger.isDebugEnabled()) {
123: logger
124: .debug("there is no principal in IPentahoSession"); //$NON-NLS-1$
125: logger
126: .debug("creating token with username anonymous and role Anonymous"); //$NON-NLS-1$
127: }
128: // Hmmm - at this point, we're being asked for an authentication on
129: // an un-authenticated user. For now, we'll default to returning
130: // an authentication that has the user as anonymous.
131: Authentication auth = new UsernamePasswordAuthenticationToken(
132: DefaultAnonymousUser,
133: null,
134: new GrantedAuthorityImpl[] { new GrantedAuthorityImpl(
135: DefaultAnonymousRole) });
136: return auth;
137: } else {
138: if (logger.isDebugEnabled()) {
139: logger
140: .debug("there is no principal in IPentahoSession"); //$NON-NLS-1$
141: logger.debug("and allowAnonymous is false"); //$NON-NLS-1$
142: }
143: // If we're here - we require a properly authenticated user and
144: // there's nothing
145: // else we can do aside from returning null.
146: return null;
147: }
148: }
149:
150: /**
151: * Gets the java.security.principal object from the IPentahoSession object
152: * @param session The users' session
153: * @return The bound Principal
154: */
155: public static Principal getPrincipal(IPentahoSession session) {
156: Principal principal = (Principal) session
157: .getAttribute(SESSION_PRINCIPAL);
158: return principal;
159: }
160:
161: /**
162: * Sets the java.security.principal object into the IPentahoSession object.
163: * @param principal The principal from the servlet context
164: * @param session The users' IPentahoSession object
165: */
166: public static void setPrincipal(Principal principal,
167: IPentahoSession session) {
168: session.setAttribute(SESSION_PRINCIPAL, principal);
169: }
170:
171: /**
172: * Utility method that communicates with the installed ACLVoter to determine
173: * administrator status
174: * @param session The users IPentahoSession object
175: * @return true if the user is considered a Pentaho administrator
176: */
177: public static boolean isPentahoAdministrator(IPentahoSession session) {
178: IAclVoter voter = PentahoSystem.getAclVoter(session);
179: return voter.isPentahoAdministrator(session);
180: }
181:
182: /**
183: * Utility method that communicates with the installed ACLVoter to determine
184: * whether a particular role is granted to the specified user.
185: * @param session The users' IPentahoSession
186: * @param role The role to look for
187: * @return true if the user is granted the specified role.
188: */
189: public static boolean isGranted(IPentahoSession session,
190: GrantedAuthority role) {
191: IAclVoter voter = PentahoSystem.getAclVoter(session);
192: return voter.isGranted(session, role);
193: }
194:
195: /**
196: * @param aFile
197: * @return a boolean that indicates if this file can have ACLS placed on it.
198: */
199: public static boolean canHaveACLS(RepositoryFile aFile) {
200: if (aFile.isDirectory()) { // All Directories can have ACLS
201: return true;
202: }
203:
204: // Otherwise anything in the PentahoSystem extension list.
205: return PentahoSystem.getACLFileExtensionList().contains(
206: aFile.getExtension());
207: }
208:
209: public static boolean hasAccess(IAclHolder aHolder,
210: int actionOperation, IPentahoSession session) {
211: IAclVoter voter = PentahoSystem.getAclVoter(session);
212: int aclMask = -1;
213:
214: switch (actionOperation) {
215: case (IAclHolder.ACCESS_TYPE_READ): {
216: aclMask = PentahoAclEntry.EXECUTE;
217: break;
218: }
219: case IAclHolder.ACCESS_TYPE_WRITE:
220: case IAclHolder.ACCESS_TYPE_UPDATE: {
221: aclMask = PentahoAclEntry.UPDATE;
222: break;
223: }
224: case IAclHolder.ACCESS_TYPE_DELETE: {
225: aclMask = PentahoAclEntry.DELETE;
226: break;
227: }
228: case IAclHolder.ACCESS_TYPE_ADMIN: {
229: aclMask = PentahoAclEntry.ADMINISTRATION;
230: break;
231: }
232: default: {
233: aclMask = PentahoAclEntry.EXECUTE;
234: break;
235: }
236:
237: }
238: return voter.hasAccess(session, aHolder, aclMask);
239: }
240:
241: /**
242: * Utility method for access negotiation. For performance, not all files will
243: * be checked against the supplied voter.
244: * @param aFile
245: * @param actionOperation
246: * @param session
247: * @return
248: */
249: public static boolean hasAccess(RepositoryFile aFile,
250: int actionOperation, IPentahoSession session) {
251: if (!aFile.isDirectory()) {
252: List extensionList = PentahoSystem
253: .getACLFileExtensionList();
254: String fName = aFile.getFileName();
255: int posn = fName.lastIndexOf('.');
256: if (posn >= 0) {
257: if (extensionList.indexOf(fName.substring(posn)) < 0) {
258: // Non-acl'd file. Return true.
259: return true;
260: }
261: } else {
262: // Untyped file. Allow access.
263: return true;
264: }
265: }
266: IAclVoter voter = PentahoSystem.getAclVoter(session);
267: int aclMask = -1;
268: switch (actionOperation) {
269: case ISolutionRepository.ACTION_EXECUTE: {
270: aclMask = PentahoAclEntry.EXECUTE;
271: break;
272: }
273: case ISolutionRepository.ACTION_ADMIN: {
274: // aclMask = PentahoAclEntry.ADMINISTRATION;
275: // break;
276: return isPentahoAdministrator(session);
277: }
278: case ISolutionRepository.ACTION_SUBSCRIBE: {
279: aclMask = PentahoAclEntry.SUBSCRIBE;
280: break;
281: }
282: case ISolutionRepository.ACTION_CREATE: {
283: aclMask = PentahoAclEntry.CREATE;
284: break;
285: }
286: case ISolutionRepository.ACTION_UPDATE: {
287: aclMask = PentahoAclEntry.UPDATE;
288: break;
289: }
290: case ISolutionRepository.ACTION_DELETE: {
291: aclMask = PentahoAclEntry.DELETE;
292: break;
293: }
294: default: {
295: aclMask = PentahoAclEntry.EXECUTE;
296: break;
297: }
298: }
299: return voter.hasAccess(session, aFile, aclMask);
300: }
301:
302: }
|