![JAR search and dependency download from the Maven repository](/logo.png)
com.sun.enterprise.security.ee.Audit Maven / Gradle / Ivy
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2012 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
// Portions Copyright [2018-2021] [Payara Foundation and/or its affiliates]
package com.sun.enterprise.security.ee;
import java.util.*;
import java.util.logging.Logger;
import java.util.logging.Level;
//V3:Commented import com.sun.enterprise.config.serverbeans.ServerBeansFactory;
import com.sun.logging.LogDomains;
import com.sun.enterprise.deployment.Application;
import com.sun.enterprise.deployment.EjbBundleDescriptor;
import com.sun.enterprise.deployment.EjbDescriptor;
import com.sun.enterprise.deployment.MethodPermission;
import com.sun.enterprise.deployment.MethodDescriptor;
import com.sun.enterprise.deployment.RunAsIdentityDescriptor;
import com.sun.enterprise.deployment.EjbIORConfigurationDescriptor;
import com.sun.enterprise.deployment.WebBundleDescriptor;
import com.sun.enterprise.deployment.web.SecurityConstraint;
import com.sun.enterprise.deployment.web.AuthorizationConstraint;
import com.sun.enterprise.deployment.web.LoginConfiguration;
import com.sun.enterprise.deployment.web.UserDataConstraint;
import com.sun.enterprise.deployment.web.SecurityRole;
import com.sun.enterprise.deployment.web.WebResourceCollection;
import com.sun.enterprise.deployment.WebComponentDescriptor;
import org.glassfish.security.common.Role;
import org.glassfish.deployment.common.SecurityRoleMapper;
import jakarta.servlet.http.HttpServletRequest;
import com.sun.appserv.security.AuditModule;
/**
* Audit support class.
*
*
* This class provides convenience methods for producing audit output. Audit output is logged using the standard iAS
* logger SECURITYLOGGER. However, audit output is only produced if auditing is active. Auditing is configured in
* server.xml in the security-service element.
*
*
* Audit output if logged with Level.WARNING.
*
*
* Some diagnostic methods are also provided for debugging.
*
*/
public class Audit extends AuditModule {
private static final String AUDIT_ON = "auditOn";
private static boolean auditFlag = false;
private static Logger logger = LogDomains.getLogger(Audit.class, LogDomains.SECURITY_LOGGER);
/*
* private static String strPrivateAudit = null; private static String strDenied = null; private static String strOK =
* null; private static String strMethodName = null; private static String strSession = null;
*/
/**
* Check auditing state.
*
* @returns True if auditing is active currently.
*
*/
public static boolean isActive() {
return auditFlag;
}
@Override
public void init(Properties props) {
super.init(props);
String audit = props.getProperty(AUDIT_ON);
auditFlag = (audit == null) ? false : Boolean.valueOf(audit).booleanValue();
}
/**
* Invoked post authentication request for a user in a given realm
*
* @param user username for whom the authentication request was made
* @param realm the realm name under which the user is authenticated.
* @param success the status of the authentication
*/
@Override
public void authentication(String user, String realm, boolean success) {
if (auditFlag) {
StringBuilder sbuf = new StringBuilder("Audit: Authentication for user = (");
sbuf.append(user);
sbuf.append(") under realm = (");
sbuf.append(realm).append(") returned = ").append(success);
logger.log(Level.INFO, sbuf.toString());
}
}
/**
* Invoked post web authorization request.
*
* @param user the username for whom the authorization was performed
* @param req the HttpRequest object for the web request
* @param type either hasResourcePermission, hasUserDataPermission or hasRoleRefPermission
* @param success the status of the web authorization request
*/
@Override
public void webInvocation(String user, HttpServletRequest req,
String type, boolean success) {
if (auditFlag) {
StringBuilder sbuf = new StringBuilder("Audit: [Web] Authorization for user = (");
sbuf.append(user).append(") and permission type = (").append(type).append(") for request ");
sbuf.append(req.getMethod()).append(" ").append(req.getRequestURI()).append(" returned =").append(success);
logger.log(Level.INFO, sbuf.toString());
}
}
/**
* Invoked post ejb authorization request.
*
* @param user the username for whom the authorization was performed
* @param ejb the ejb name for which this authorization was performed
* @param method the method name for which this authorization was performed
* @param success the status of the ejb authorization request
*/
@Override
public void ejbInvocation(String user, String ejb, String method, boolean success) {
if (auditFlag) {
// Modified from StringBuilder to StringBuilder
StringBuilder sbuf = new StringBuilder("Audit: [EJB] Authorization for user =");
sbuf.append(user).append(" for ejb = (");
sbuf.append(ejb).append(") method = (").append(method).append(") returned =").append(success);
logger.log(Level.INFO, sbuf.toString());
}
}
/**
* Invoked post ejb authorization request.
*
* @param user the username for whom the authorization was performed
* @param ejb the ejb name for which this authorization was performed
* @param method the method name for which this authorization was performed
* @param success the status of the ejb authorization request
*/
/**
* Invoked during validation of the web service request
*
* @param uri The URL representation of the web service endpoint
* @param endpoint The name of the endpoint representation
* @param success the status of the web service request validation
*/
@Override
public void webServiceInvocation(String uri, String endpoint, boolean success) {
if (auditFlag) {
StringBuilder sbuf = new StringBuilder("Audit: [WebService] ");
sbuf.append("uri: ").append(uri);
sbuf.append("endpoint: ").append(endpoint);
sbuf.append(", valid request =").append(success);
logger.log(Level.INFO, sbuf.toString());
}
}
/**
* Invoked during validation of the web service request
*
* @param endpoint The URL representation of the web service endpoint
* @param success the status of the web service request validation
*/
@Override
public void ejbAsWebServiceInvocation(String endpoint, boolean success) {
if (auditFlag) {
StringBuilder sbuf = new StringBuilder("Audit: [EjbAsWebService] ");
sbuf.append("endpoint : ").append(endpoint).append(", valid request =").append(success);
logger.log(Level.INFO, sbuf.toString());
}
}
/**
* Invoked upon completion of the server startup
*/
@Override
public void serverStarted() {
if (auditFlag) {
logger.log(Level.INFO, "Audit: Application server startup complete");
}
}
/**
* Invoked upon completion of the server shutdown
*/
@Override
public void serverShutdown() {
if (auditFlag) {
logger.log(Level.INFO, "Audit: Application server shutdown complete");
}
}
/**
* Initialize auditing. This reads the server.xml configuration to determine whether audit is turned on or off.
*
*/
/*
* public static void init() { try { ConfigContext configContext =
* ApplicationServer.getServerContext().getConfigContext(); assert(configContext != null); Server configBean =
* ServerBeansFactory.getServerBean(configContext); assert(configBean != null); SecurityService securityBean =
* ServerBeansFactory.getSecurityServiceBean(configContext); assert(securityBean != null); auditFlag =
* securityBean.isAuditEnabled(); } catch (Exception e) { logger.log(Level.WARNING, "audit.badinit", e); } if
* (auditFlag) { logger.info("audit.enabled"); } // load i18n message bits for audit entries ResourceBundle resBundle =
* logger.getResourceBundle(); strPrivateAudit = resBundle.getString("audit.string_private_audit"); strDenied = " " +
* resBundle.getString("audit.denied"); strOK = " " + resBundle.getString("audit.ok"); strMethodName = " " +
* resBundle.getString("audit.methodname"); strSession = " " + resBundle.getString("audit.session"); }
*/
/**
* Log an EJB method invocation.
*
* @param user Effective user for the invocation.
* @param ejb EJB name.
* @param method Method name.
* @param success True if the invocation was allowed, false if denied.
*
*/
/*
* public static void ejbMethodInvocation(SecurityContext secCtx, EJBLocalRemoteObject ejbObj, Method method, boolean
* success) { if (!logger.isLoggable(Level.INFO)) { return; } String user = "(null)"; if (secCtx != null) { Principal p
* = secCtx.getCallerPrincipal(); if (p!=null) { user = p.getName(); } } String ejb = "(N/A)"; if (ejbObj != null) { ejb
* = ejbObj.toString(); } String meth = "(N/A)"; if (method != null) { meth = method.toString(); } StringBuilder sb = new
* StringBuilder(); sb.append(strPrivateAudit); // "Audit: principal=" if(user != null) { sb.append(user); } else {
* sb.append("(null)"); } sb.append(" ejb="); sb.append(ejb); sb.append(strMethodName); // " method=" sb.append(method);
* if (success) { sb.append(strOK); // " OK" } else { sb.append(strDenied); // " DENIED" } logger.info(sb.toString()); }
*/
/**
* Log a servlet invocation.
*
* @param req The HttpRequest.
* @param success True if the invocation was allowed, false if denied.
*
*/
/*
* public static void webInvocation(HttpRequest req, boolean success) { /// DO NOTHING FOR NOW. //if
* (!logger.isLoggable(Level.INFO) || !auditFlag) { // return; //} //if (req == null) { //
* logger.fine("Audit: No HttpRequest available."); // return; //} //if (!(req instanceof HttpRequestBase)) { //
* logger.fine("Audit internal error, class: " + req.getClass()); // return; //} //HttpRequestBase reqs =
* (HttpRequestBase)req; //StringBuilder sb = new StringBuilder(); //sb.append(strPrivateAudit); // "Audit: principal="
* //String user = reqs.getRemoteUser(); //if (user != null) { // sb.append(user); //} else { // sb.append("(null)");
* //} //sb.append(" "); //sb.append(reqs.getMethod()); //sb.append(" "); //sb.append(reqs.getRequestURI());
* //sb.append(strSession); // " session=" //sb.append(reqs.getRequestedSessionId()); //if (success) { //
* sb.append(strOK); // " OK" //} else { // sb.append(strDenied); // " DENIED" //} //logger.info(sb.toString()); }
*/
/**
* Diagnostic method. Read roles and ACLs from the given Application and dump a somewhat organized summary of what has
* been set. This can be used to diagnose deployment or runtime deployment errors as well as to help in configuring
* application descriptors.
*
*
* Implementation is not particularly efficient but this is only called for debugging purposes at startup. All errors
* are ignored.
*
* @param app Application object to analyze.
*
*/
public static void showACL(Application app) {
if (!isActive() || !logger.isLoggable(Level.FINEST)) {
return;
}
try {
dumpDiagnostics(app);
} catch (Throwable e) {
logger.fine("Error while showing ACL diagnostics: " +
e.toString());
}
}
/**
* Do the work for showACL().
*
*/
private static void dumpDiagnostics(Application app) {
logger.finest("====[ Role and ACL Summary ]==========");
if (!app.isVirtual()) {
logger.finest("Summary for application: " +
app.getRegistrationName());
} else {
logger.finest("Standalone module.");
}
logger.finest("EJB components: " +
getEjbComponentCount(app));
logger.finest("Web components: " +
getWebComponentCount(app));
Iterator i;
StringBuilder sb;
// show all roles with associated group & user mappings
Set allRoles = app.getRoles();
if (allRoles == null) {
logger.finest("- No roles present.");
return;
}
SecurityRoleMapper rmap = app.getRoleMapper();
if (rmap == null) {
logger.finest("- No role mappings present.");
return;
}
i = allRoles.iterator();
logger.finest("--[ Configured roles and mappings ]--");
HashMap allRoleMap = new HashMap();
while (i.hasNext()) {
Role r = (Role) i.next();
logger.finest(" [" + r.getName() + "]");
allRoleMap.put(r.getName(), new HashSet());
sb = new StringBuilder();
sb.append(" is mapped to groups: ");
Enumeration grps = rmap.getGroupsAssignedTo(r);
while (grps.hasMoreElements()) {
sb.append(grps.nextElement());
sb.append(" ");
}
logger.finest(sb.toString());
sb = new StringBuilder();
sb.append(" is mapped to principals: ");
Enumeration users = rmap.getUsersAssignedTo(r);
while (users.hasMoreElements()) {
sb.append(users.nextElement());
sb.append(" ");
}
logger.finest(sb.toString());
}
// Process all EJB modules
Set ejbDescriptorSet = app.getBundleDescriptors(EjbBundleDescriptor.class);
i = ejbDescriptorSet.iterator();
while (i.hasNext()) {
EjbBundleDescriptor bundle = (EjbBundleDescriptor) i.next();
logger.finest("--[ EJB module: " + bundle.getName() + " ]--");
Set ejbs = bundle.getEjbs();
Iterator it = ejbs.iterator();
while (it.hasNext()) {
EjbDescriptor ejb = (EjbDescriptor) it.next();
logger.finest("EJB: " + ejb.getEjbClassName());
// check and show run-as if present
if (!ejb.getUsesCallerIdentity()) {
RunAsIdentityDescriptor runas = ejb.getRunAsIdentity();
if (runas == null) {
logger.finest(" (ejb does not use caller " +
"identity)");
} else {
String role = runas.getRoleName();
String user = runas.getPrincipal();
logger.finest(" Will run-as: Role: " + role +
" Principal: " + user);
if (role == null || "".equals(role) ||
user == null || "".equals(user)) {
if (logger.isLoggable(Level.FINEST)) {
logger.finest("*** Configuration error!");
}
}
}
}
// iterate through available methods
logger.finest(" Method to Role restriction list:");
Set methods = ejb.getMethodDescriptors();
Iterator si = methods.iterator();
while (si.hasNext()) {
MethodDescriptor md = (MethodDescriptor) si.next();
logger.finest(" " + md.getFormattedString());
Set perms = ejb.getMethodPermissionsFor(md);
StringBuilder rbuf = new StringBuilder();
rbuf.append(" can only be invoked by: ");
Iterator sip = perms.iterator();
boolean unchecked = false, excluded = false, roleBased = false;
while (sip.hasNext()) {
MethodPermission p = (MethodPermission) sip.next();
if (p.isExcluded()) {
excluded = true;
logger.finest(" excluded - can not " +
"be invoked");
} else if (p.isUnchecked()) {
unchecked = true;
logger.finest(" unchecked - can be " +
"invoked by all");
} else if (p.isRoleBased()) {
roleBased = true;
Role r = p.getRole();
rbuf.append(r.getName());
rbuf.append(" ");
// add to role's accessible list
HashSet ram = (HashSet) allRoleMap.get(r.getName());
ram.add(bundle.getName() + ":" +
ejb.getEjbClassName() + "." +
md.getFormattedString());
}
}
if (roleBased) {
logger.finest(rbuf.toString());
if (excluded || unchecked) {
logger.finest("*** Configuration error!");
}
} else if (unchecked) {
if (excluded) {
logger.finest("*** Configuration error!");
}
Set rks = allRoleMap.keySet();
Iterator rksi = rks.iterator();
while (rksi.hasNext()) {
HashSet ram = (HashSet) allRoleMap.get(rksi.next());
ram.add(bundle.getName() + ":" +
ejb.getEjbClassName() + "." +
md.getFormattedString());
}
} else if (!excluded) {
logger.finest("*** Configuration error!");
}
}
// IOR config for this ejb
logger.finest(" IOR configuration:");
Set iors = ejb.getIORConfigurationDescriptors();
if (iors != null) {
Iterator iorsi = iors.iterator();
while (iorsi.hasNext()) {
EjbIORConfigurationDescriptor ior = (EjbIORConfigurationDescriptor) iorsi.next();
StringBuilder iorsb = new StringBuilder();
iorsb.append("realm=");
iorsb.append(ior.getRealmName());
iorsb.append(", integrity=");
iorsb.append(ior.getIntegrity());
iorsb.append(", trust-in-target=");
iorsb.append(ior.getEstablishTrustInTarget());
iorsb.append(", trust-in-client=");
iorsb.append(ior.getEstablishTrustInClient());
iorsb.append(", propagation=");
iorsb.append(ior.getCallerPropagation());
iorsb.append(", auth-method=");
iorsb.append(ior.getAuthenticationMethod());
logger.finest(iorsb.toString());
}
}
}
}
// show role->accessible methods list
logger.finest("--[ EJB methods accessible by role ]--");
Set rks = allRoleMap.keySet();
Iterator rksi = rks.iterator();
while (rksi.hasNext()) {
String roleName = (String) rksi.next();
logger.finest(" [" + roleName + "]");
HashSet ram = (HashSet) allRoleMap.get(roleName);
Iterator rami = ram.iterator();
while (rami.hasNext()) {
String meth = (String) rami.next();
logger.finest(" " + meth);
}
}
// Process all Web modules
Set webDescriptorSet = app.getBundleDescriptors(WebBundleDescriptor.class);
i = webDescriptorSet.iterator();
while (i.hasNext()) {
WebBundleDescriptor wbd = (WebBundleDescriptor) i.next();
logger.finest("--[ Web module: " + wbd.getContextRoot() + " ]--");
// login config
LoginConfiguration lconf = wbd.getLoginConfiguration();
if (lconf != null) {
logger.finest(" Login config: realm=" +
lconf.getRealmName() + ", method=" +
lconf.getAuthenticationMethod() + ", form=" +
lconf.getFormLoginPage() + ", error=" +
lconf.getFormErrorPage());
}
// get WebComponentDescriptorsSet() info
logger.finest(" Contains components:");
Set webComps = wbd.getWebComponentDescriptors();
Iterator webCompsIt = webComps.iterator();
while (webCompsIt.hasNext()) {
WebComponentDescriptor wcd = (WebComponentDescriptor) webCompsIt.next();
StringBuilder name = new StringBuilder();
name.append(" - " + wcd.getCanonicalName());
name.append(" [ ");
Enumeration urlPs = wcd.getUrlPatterns();
while (urlPs.hasMoreElements()) {
name.append(urlPs.nextElement().toString());
name.append(" ");
}
name.append("]");
logger.finest(name.toString());
RunAsIdentityDescriptor runas = wcd.getRunAsIdentity();
if (runas != null) {
String role = runas.getRoleName();
String user = runas.getPrincipal();
logger.finest(" Will run-as: Role: " + role +
" Principal: " + user);
if (role == null || "".equals(role) ||
user == null || "".equals(user)) {
logger.finest("*** Configuration error!");
}
}
}
// security constraints
logger.finest(" Security constraints:");
Enumeration scEnum = wbd.getSecurityConstraints();
while (scEnum.hasMoreElements()) {
SecurityConstraint sc = (SecurityConstraint) scEnum.nextElement();
for (WebResourceCollection wrc : sc.getWebResourceCollections()) {
// show list of methods for this collection
StringBuilder sbm = new StringBuilder();
for (String httpMethod : wrc.getHttpMethods()) {
sbm.append(httpMethod);
sbm.append(" ");
}
logger.finest(" Using method: " + sbm.toString());
// and then list of url patterns
for (String urlPattern : wrc.getUrlPatterns()) {
logger.finest(" " + urlPattern);
}
} // end res.collection iterator
// show roles which apply to above set of collections
AuthorizationConstraint authCons = sc.getAuthorizationConstraint();
Enumeration rolesEnum = authCons.getSecurityRoles();
StringBuilder rsb = new StringBuilder();
rsb.append(" Accessible by roles: ");
while (rolesEnum.hasMoreElements()) {
SecurityRole sr = (SecurityRole) rolesEnum.nextElement();
rsb.append(sr.getName());
rsb.append(" ");
}
logger.finest(rsb.toString());
// show transport guarantee
UserDataConstraint udc = sc.getUserDataConstraint();
if (udc != null) {
logger.finest(" Transport guarantee: " +
udc.getTransportGuarantee());
}
} // end sec.constraint
} // end webDescriptorSet.iterator
logger.finest("======================================");
}
/**
* The number of Web Components in this application. Current implementation only return the number of servlets inside
* the application, and not the JSPs since we cannot get that information from deployment descriptors.
*
* @return the number of Web Components
*/
private static int getWebComponentCount(Application app) {
int count = 0;
for (WebBundleDescriptor wbd : app.getBundleDescriptors(WebBundleDescriptor.class)) {
count = count + wbd.getWebComponentDescriptors().size();
}
return count;
}
/**
* The number of EJB JARs in this application.
*
* @return the number of EJB JARS
*/
private static int getEjbComponentCount(Application app) {
int count = 0;
for (EjbBundleDescriptor ejbd : app.getBundleDescriptors(EjbBundleDescriptor.class)) {
count = count + ejbd.getEjbs().size();
}
return count;
}
}