blob: baf52774742f65b72216e32ab00581e7d630be7e [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*/
package org.apache.directory.fortress.web.control;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.directory.fortress.core.*;
import org.apache.directory.fortress.core.SecurityException;
import org.apache.directory.fortress.core.util.Config;
import org.apache.directory.fortress.core.model.UserRole;
import org.apache.directory.fortress.core.model.Warning;
import org.apache.directory.fortress.realm.*;
import org.apache.directory.fortress.realm.GlobalIds;
import org.apache.wicket.Component;
import org.apache.directory.fortress.core.model.Permission;
import org.apache.directory.fortress.core.model.Session;
import org.apache.directory.fortress.core.model.User;
import org.apache.wicket.ajax.AjaxRequestTarget;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import jakarta.servlet.http.HttpServletRequest;
import java.security.Principal;
import java.util.List;
/**
* Common static utils and wrappers used by Wicket web apps to make fortress style security calls.
*
* @author <a href="mailto:dev@directory.apache.org">Apache Directory Project</a>
* @version $Rev$
*/
public class SecUtils
{
//private static final Logger LOG = LoggerFactory.getLogger( SecUtils.class.getName() );
private static final Logger LOG = LoggerFactory.getLogger( SecUtils.class.getName() );
private static final String PERMS_CACHED = "perms.cached";
public static final boolean IS_PERM_CACHED = ( ( Config.getInstance().getProperty( PERMS_CACHED ) != null ) && ( Config.getInstance()
.getProperty( PERMS_CACHED ).equalsIgnoreCase( "true" ) ) );
/**
* Return the fortress session that is cached within the wicket session object.
*
* @param component needed to get handle to wicket session.
* @return fortress session object.
*/
public static Session getSession(Component component)
{
return ( ( WicketSession ) component.getSession() ).getSession();
}
/**
* Used when web app needs to create a 'trusted' fortress session.
*
* Does not check user's password.
*
* @param accessMgr fortress access mgr apis
* @param userId required for rbac session creation.
* @return rbac session.
*/
public static Session createSession(AccessMgr accessMgr, String userId)
{
Session session;
try
{
// Create an RBAC session and attach to Wicket session:
session = accessMgr.createSession( new User( userId ), true );
String message = "RBAC Session successfully created for userId: " + session.getUserId();
LOG.debug( message );
}
catch ( org.apache.directory.fortress.core.SecurityException se )
{
String error = "createSession caught SecurityException=" + se;
LOG.error( error );
throw new RuntimeException( error );
}
return session;
}
/**
* Here the wicket session is loaded with the fortress session and permissions.
*
*
* @param delAccessMgr needed to pull back fortress arbac permissions.
* @param session needed for call into accessMgr.
*/
public static void loadPermissionsIntoSession( DelAccessMgr delAccessMgr, Session session)
{
try
{
// Retrieve user permissions and attach fortress session to Wicket session:
( ( WicketSession ) WicketSession.get() ).setSession( session );
List<Permission> permissions = delAccessMgr.sessionPermissions( session );
( ( WicketSession ) WicketSession.get() ).setPermissions( permissions );
String message = "Session successfully created for userId: " + session.getUserId();
LOG.debug( message );
}
catch ( org.apache.directory.fortress.core.SecurityException se )
{
String error = "loadPermissionsIntoSession caught SecurityException=" + se;
LOG.error( error );
throw new RuntimeException( error );
}
}
/**
* Returns the fortress arbac perms that are cashed in the wicket session.
*
* @param component needed to get a handle on the wicket session object.
* @return collection of fortress admin perms.
*/
public static List<Permission> getPermissions(Component component)
{
List<Permission> perms;
try
{
WicketSession wSess = ( WicketSession )component.getSession();
perms = wSess.getPermissions();
}
catch(Exception e)
{
String error = "getPermissions caught Exception=" + e;
LOG.error( error );
throw new RuntimeException( error );
}
return perms;
}
/**
* Retrieve RBAC session permissions from Fortress and place in the Wicket session.
*/
public static void getPermissions( Component component, AccessMgr accessMgr )
{
try
{
if ( IS_PERM_CACHED )
{
WicketSession session = ( WicketSession ) component.getSession();
List<Permission> permissions = accessMgr.sessionPermissions( session.getSession() );
( ( WicketSession ) WicketSession.get() ).setPermissions( permissions );
}
}
catch ( org.apache.directory.fortress.core.SecurityException se )
{
String error = "getPermissions caught SecurityException=" + se;
LOG.error( error );
throw new RuntimeException( error );
}
}
/**
* Wrapper for the httpservlet isUserInRole api.
*
* @param roleName contains the name of role being checked.
* @param servletReq handle used to make inquiry.
* @return true if authorized, false otherwise.
*/
public static boolean isAuthorized( String roleName, HttpServletRequest servletReq )
{
boolean isAuthorized = false;
if ( servletReq.isUserInRole( roleName ) )
{
isAuthorized = true;
}
return isAuthorized;
}
/**
* Is the supplied permission in the wicket session cache? Called by buttons.
* if not found, button will be invisible.
*
* @param permission fortress perm requires {link @Permission#objName} and {link @Permission#opName} are set.
* @param component needed to get handle on the wicket session object.
* @return true if found, false otherwise
*/
public static boolean isFound( Permission permission, Component component )
{
List<Permission> permissions = SecUtils.getPermissions( component );
return CollectionUtils.isNotEmpty( permissions ) && permissions.contains( permission );
}
/**
* Wrapper to fortress checkAccess api.
*
* @param component contains the wicket session handle.
* @param accessMgr has the checkAccess api
* @param objName string value
* @param opName string value
* @param objId string value
* @return true if success, false otherwise.
* @throws org.apache.directory.fortress.core.SecurityException checked exception for system errors.
*/
public static boolean checkAccess(Component component, AccessMgr accessMgr, String objName, String opName, String objId ) throws org.apache.directory.fortress.core.SecurityException
{
WicketSession session = ( WicketSession )component.getSession();
Permission permission = new Permission( objName, opName, objId );
return accessMgr.checkAccess( session.getSession(), permission );
}
/**
* Convert the principal into fortress session and load into wicket session along with perms.
*
* @param component contains handle to wicket session.
* @param j2eePolicyMgr used to call deserize api
* @param accessMgr used to call fortress api for role op
* @param szPrincipal contains the instance of fortress session deserialized.
*/
public static void initializeSession(Component component, J2eePolicyMgr j2eePolicyMgr, AccessMgr accessMgr, String szPrincipal ) throws SecurityException
{
Session realmSession = null;
if(j2eePolicyMgr == null || accessMgr == null)
{
throw new SecurityException( GlobalIds.SESSION_INITIALIZATION_FAILED, "initializeSession failed - verify the injection of fortress spring beans into your application" );
}
try
{
if( StringUtils.isNotEmpty( szPrincipal ))
realmSession = j2eePolicyMgr.deserialize( szPrincipal );
}
catch( SecurityException se )
{
throw new RuntimeException( se );
}
if(realmSession != null)
{
synchronized ( ( WicketSession ) WicketSession.get() )
{
if ( SecUtils.getSession( component ) == null )
{
LOG.info( "realmSession user: " + realmSession.getUserId() );
// Retrieve user permissions and attach RBAC session to Wicket session:
( ( WicketSession ) WicketSession.get() ).setSession( realmSession );
getPermissions( component, accessMgr );
}
}
}
}
/**
* Call RBAC addActiveRole to activate a new role into user's session.
* This routine must first retrieves the wicket session.
* It is needed because it contains the fortress session which is required for api.
* Next it invokes the fortress addActiveRole method.
* If all successful refresh user's perms cached as they've changed.
*
* @param component contains handle to wicket session.
* @param target used to display modal if something goes wrong
* @param accessMgr used to call fortress api for role op
* @param roleName contains the role name target
* @return true if success, false otherwise.
*/
public static boolean addActiveRole( Component component, AjaxRequestTarget target, AccessMgr accessMgr, String roleName )
{
boolean isSuccessful = false;
try
{
WicketSession session = ( WicketSession ) component.getSession();
session.getSession().setWarnings( null );
accessMgr.addActiveRole( session.getSession(), new UserRole( roleName ) );
List<Warning> warnings = session.getSession().getWarnings();
if ( CollectionUtils.isNotEmpty( warnings ) )
{
for ( Warning warning : warnings )
{
LOG.info( "Warning: " + warning.getMsg() + " errCode: " + warning.getId() + " name: " + warning
.getName() + " type: " + warning.getType().toString() );
if ( warning.getType() == Warning.Type.ROLE && warning.getName().equalsIgnoreCase( roleName ) )
{
String error = warning.getMsg() + " code: " + warning.getId();
LOG.error( error );
target.appendJavaScript( ";alert('" + error + "');" );
return false;
}
}
}
// User's active role set changed so refresh their permissions:
SecUtils.getPermissions( component, accessMgr );
isSuccessful = true;
String message = "Activate role name: " + roleName + " successful";
LOG.info( message );
}
catch ( org.apache.directory.fortress.core.SecurityException se )
{
String msg = "Role selection " + roleName + " activation failed because of ";
if ( se.getErrorId() == GlobalErrIds.DSD_VALIDATION_FAILED )
{
msg += "Dynamic SoD rule violation";
}
else if ( se.getErrorId() == GlobalErrIds.URLE_ALREADY_ACTIVE )
{
msg += "Role already active in Session";
}
else
{
msg += "System error: " + se + ", " + "errId=" + se.getErrorId();
}
LOG.error( msg );
target.appendJavaScript( ";alert('" + msg + "');" );
}
return isSuccessful;
}
/**
* Call RBAC dropActiveRole to deactivate a new role from user's session.
* This routine must first retrieves the wicket session.
* It is needed because it contains the fortress session which is required for api.
* Next it invokes the fortress dropActiveRole method.
* If all successful refresh user's perms cached as they've changed.
*
* @param component contains handle to wicket session.
* @param target used to display modal if something goes wrong
* @param accessMgr used to call fortress api for role op
* @param roleName contains the role name target
* @return true if success, false otherwise.
*/
public static boolean dropActiveRole( Component component, AjaxRequestTarget target, AccessMgr accessMgr, String roleName )
{
boolean isSuccessful = false;
try
{
WicketSession session = ( WicketSession ) component.getSession();
accessMgr.dropActiveRole( session.getSession(), new UserRole( roleName ) );
// User's active role set changed so refresh their permissions:
SecUtils.getPermissions( component, accessMgr );
isSuccessful = true;
LOG.info( "Fortress dropActiveRole roleName: " + roleName + " was successful" );
}
catch ( SecurityException se )
{
String msg = "Role selection " + roleName + " deactivation failed because of ";
if ( se.getErrorId() == GlobalErrIds.URLE_NOT_ACTIVE )
{
msg += "Role not active in session";
}
else
{
msg += "System error: " + se + ", " + "errId=" + se.getErrorId();
}
LOG.error( msg );
target.appendJavaScript( ";alert('" + msg + "');" );
}
return isSuccessful;
}
/**
* Enables fortress session on behalf of a java.security.Principal retrieved from the container.
*
* @param component
* @param servletReq
* @param j2eePolicyMgr
* @param accessMgr
* @throws SecurityException
*/
public static void enableFortress( Component component, HttpServletRequest servletReq, J2eePolicyMgr j2eePolicyMgr, AccessMgr accessMgr ) throws SecurityException
{
// Get the principal from the container:
Principal principal = servletReq.getUserPrincipal();
// Is this a Java EE secured page && has the User successfully authenticated already?
boolean isSecured = principal != null;
if(isSecured)
{
//linksLabel += " for " + principal.getName();
if( !isLoggedIn( component ) )
{
String szPrincipal = principal.toString();
// Pull the fortress session from the realm and assert into the Web app's session along with user's perms:
SecUtils.initializeSession( component, j2eePolicyMgr, accessMgr, szPrincipal );
}
}
}
/**
* If user has a wicket session then considered logged in.
*
* @return true if wicket session is not null
*/
public static boolean isLoggedIn( Component component )
{
boolean isLoggedIn = false;
if ( getSession( component ) != null )
{
isLoggedIn = true;
}
return isLoggedIn;
}
public static Permission getPermFromId( String id )
{
Permission perm = null;
String[] parts = id.split( "\\." );
if( parts.length > 1)
{
String objName = parts[0];
String opName = parts[1];
perm = new Permission( objName, opName );
}
return perm;
}
}