diff --git a/appserver/admingui/common/src/main/resources/org/glassfish/common/admingui/Strings.properties b/appserver/admingui/common/src/main/resources/org/glassfish/common/admingui/Strings.properties index 9a1193900c5..c51977da03c 100644 --- a/appserver/admingui/common/src/main/resources/org/glassfish/common/admingui/Strings.properties +++ b/appserver/admingui/common/src/main/resources/org/glassfish/common/admingui/Strings.properties @@ -78,6 +78,8 @@ security.Security=Security security.SecurityPageHelp=Set security properties for the entire server. security.SecurityManager=Security Manager security.SecurityManagerHelp=Enable the security manager for the domain by adding an option in the JVM Settings +security.AdminAudit=Admin Audit +security.AdminAuditHelp=Audit admin commands security.AuditLogging=Enable Audit Modules security.AuditLoggingHelp=Enable server to load and run all audit modules specified in the Audit Modules setting security.DefaultRealm=Default Realm @@ -103,7 +105,6 @@ security.secureAdmin.instancealias=Instance Alias: security.secureAdmin.instancealiasHelp=The alias that refers to the SSL/TLS certificate on the instances. This alias is used by the DAS to authenticate against the instances. security.secureLabel=Secure Administration: - ## Realms realm.NewPageTitle=New Realm realm.NewPageHelp=Create a new security (authentication) realm. Valid realm types are PAM, OSGi, File, Certificate, LDAP, JDBC, Digest, Oracle Solaris, and Custom. diff --git a/appserver/admingui/common/src/main/resources/pluginTreeNodeSecurity.jsf b/appserver/admingui/common/src/main/resources/pluginTreeNodeSecurity.jsf index e3cb79a2c78..9c2a9dca012 100644 --- a/appserver/admingui/common/src/main/resources/pluginTreeNodeSecurity.jsf +++ b/appserver/admingui/common/src/main/resources/pluginTreeNodeSecurity.jsf @@ -39,6 +39,7 @@ holder. --> + @@ -50,6 +51,25 @@ + + + + + + + + + + + + + + + + + + + +#include "/common/shared/alertMsg.inc" + + + + + + + + + + + + + +#include "/common/shared/configNameSection.inc" + + + + + + + + + + + + "

+
+ + + + + + + + + + + + + + + +
+ +
+ + diff --git a/appserver/admingui/core/src/main/resources/org/glassfish/admingui/core/Strings.properties b/appserver/admingui/core/src/main/resources/org/glassfish/admingui/core/Strings.properties index 03fdecf72c3..5ebe42b377e 100644 --- a/appserver/admingui/core/src/main/resources/org/glassfish/admingui/core/Strings.properties +++ b/appserver/admingui/core/src/main/resources/org/glassfish/admingui/core/Strings.properties @@ -131,6 +131,7 @@ tree.security=Security tree.security.tooltip=Security tree.availabilityService=Availability Service tree.availabilityService.tooltip=Availability Service +tree.adminAudit=Admin Audit tree.realms=Realms tree.jaccProviders=JACC Providers tree.auditModules=Audit Modules @@ -1203,3 +1204,25 @@ cdi.cdiServicePageTitle=CDI Service Configuration cdi.cdiServicePageTitleHelp= cdi.implicitScanning=Implicit CDI Scanning cdi.implicitScanningHelp= + +# Admin audit service +adminaudit.PageTitle=Admin Audit Service +adminaudit.PageHelp=Admin AuditPageHelp +adminAudit.PageTitle=Admin Audit +adminaudit.PageHelp=Options for the admin commands audit system +adminAudit.Title=AdminAudit +adminaudit.Title=Admin Audit +adminAudit.PageTitle=Admin Audit +adminaudit.PageHelp=Options for the admin commands audit system +adminaudit.Title=Admin Audit +adminaudit.Enabled=Enabled +adminaudit.EnabledHelp=Enable the admin audit service +adminaudit.Dynamic=Dynamic +adminaudit.DynamicHelp=Make the changes take effect immediately +adminaudit.UnitLabel=Audit Level +adminaudit.UnitLabelHelp=The level of admin commands to audit +adminaudit.configuration.availableNotifiers=Available Notifiers +adminaudit.configuration.selectedNotifiers=Selected Notifiers +adminaudit.link.to.notification.page.text.prefix=Selected Notifiers need to be enabled also in the +adminaudit.link.to.notification.page.text=Notification Service +adminaudit.link.to.notification.page.text.suffix=to receive notifications. \ No newline at end of file diff --git a/appserver/admingui/core/src/main/resources/templates/menu.inc b/appserver/admingui/core/src/main/resources/templates/menu.inc index 35b21e83341..46903dc7994 100644 --- a/appserver/admingui/core/src/main/resources/templates/menu.inc +++ b/appserver/admingui/core/src/main/resources/templates/menu.inc @@ -39,6 +39,7 @@ holder. --> + @@ -77,6 +78,7 @@ + diff --git a/appserver/admingui/payara-console-extras/src/main/java/fish/payara/admingui/extras/rest/PayaraRestApiHandlers.java b/appserver/admingui/payara-console-extras/src/main/java/fish/payara/admingui/extras/rest/PayaraRestApiHandlers.java index 142e09aacc5..b1b1bf9d71b 100644 --- a/appserver/admingui/payara-console-extras/src/main/java/fish/payara/admingui/extras/rest/PayaraRestApiHandlers.java +++ b/appserver/admingui/payara-console-extras/src/main/java/fish/payara/admingui/extras/rest/PayaraRestApiHandlers.java @@ -1,5 +1,5 @@ /* - * Copyright (c) [2016-2018] Payara Foundation and/or its affiliates. All rights reserved. + * Copyright (c) [2016-2019] Payara Foundation 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 @@ -574,10 +574,12 @@ public static void updateNotifiers(HandlerContext handlerCtx) { boolean forRequestTracing = false; boolean forHealthCheck = false; boolean forMonitoring = false; + boolean forAdminAudit = false; for (String notifier : notifiers){ String name = notifier.split("-")[1]; String restEndpoint; + Map attributes = new HashMap<>(); if (endpoint.contains("request-tracing-service-configuration")){ restEndpoint = endpoint + "/requesttracing-" + name + "-notifier-configure"; forRequestTracing = true; @@ -587,21 +589,29 @@ public static void updateNotifiers(HandlerContext handlerCtx) { } else if (endpoint.contains("monitoring-service-configuration")){ restEndpoint = endpoint + "/monitoring-" + name + "-notifier-configure"; forMonitoring = true; + } else if (endpoint.contains("admin-audit-configuration")) { + restEndpoint = endpoint + "/set-admin-audit-service-notifier-configuration"; + attributes.put("notifier", name); + forAdminAudit = true; } else { //Unknown service being configured throw new UnknownConfigurationException(); } - HashMap attrs = new HashMap<>(); + if (enabledNotifiers.contains(notifier)){ - attrs.put("enabled", "true"); + attributes.put("enabled", "true"); + } else { + attributes.put("enabled", "false"); + } + if (!forAdminAudit) { + //PAYARA-1616 go silent, bootstrap will take place after iteration. + attributes.put("dynamic", "false"); } else { - attrs.put("enabled", "false"); + attributes.put("dynamic", "true"); } - //PAYARA-1616 go silent, bootstrap will take place after iteration. - attrs.put("dynamic", "false"); - attrs.put("target", target); - RestUtil.restRequest(restEndpoint, attrs, "post", handlerCtx, quiet, throwException); + attributes.put("target", target); + RestUtil.restRequest(restEndpoint, attributes, "post", handlerCtx, quiet, throwException); } // PAYARA-1616 // manually bootstrap healthCheck and requestTracing services for once so that it doesn't get bootstrapped each time for enabled notifier. @@ -814,4 +824,4 @@ public static void createDeploymentGroupInstances(HandlerContext handlerCtx) { } } -} \ No newline at end of file +} diff --git a/appserver/payara-appserver-modules/notification-datadog-core/src/main/java/fish/payara/notification/datadog/DatadogNotifierService.java b/appserver/payara-appserver-modules/notification-datadog-core/src/main/java/fish/payara/notification/datadog/DatadogNotifierService.java index 94273b40ef4..53f59e31e0a 100644 --- a/appserver/payara-appserver-modules/notification-datadog-core/src/main/java/fish/payara/notification/datadog/DatadogNotifierService.java +++ b/appserver/payara-appserver-modules/notification-datadog-core/src/main/java/fish/payara/notification/datadog/DatadogNotifierService.java @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright (c) 2017 Payara Foundation and/or its affiliates. All rights reserved. + * Copyright (c) 2017-2019 Payara Foundation 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 @@ -66,7 +66,7 @@ public class DatadogNotifierService extends QueueBasedNotifierServiceprovided + + fish.payara.payara-modules + asadmin-audit + ${project.version} + fish.payara.payara-modules asadmin-recorder diff --git a/nucleus/admin/rest/rest-service/src/main/java/org/glassfish/admin/rest/utils/ResourceUtil.java b/nucleus/admin/rest/rest-service/src/main/java/org/glassfish/admin/rest/utils/ResourceUtil.java index 2896a18f0ac..0d16f832c22 100644 --- a/nucleus/admin/rest/rest-service/src/main/java/org/glassfish/admin/rest/utils/ResourceUtil.java +++ b/nucleus/admin/rest/rest-service/src/main/java/org/glassfish/admin/rest/utils/ResourceUtil.java @@ -39,10 +39,13 @@ */ // Portions Copyright [2016-2019] [Payara Foundation and/or its affiliates] + package org.glassfish.admin.rest.utils; import com.sun.enterprise.config.serverbeans.Config; import com.sun.enterprise.config.serverbeans.Domain; + +import fish.payara.audit.AdminAuditService; import fish.payara.asadmin.recorder.AsadminRecorderService; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -247,17 +250,20 @@ public static RestActionReporter runCommand(String commandName, ParameterMap parameters, Subject subject, boolean managedJob) { - AsadminRecorderService asadminRecorderService = Globals. - getDefaultHabitat().getService(AsadminRecorderService.class); - if (asadminRecorderService.isEnabled()) { + AsadminRecorderService asadminRecorderService = Globals.get(AsadminRecorderService.class); + if (asadminRecorderService != null && asadminRecorderService.isEnabled()) { asadminRecorderService.recordAsadminCommand(commandName, parameters); - } + } + + AdminAuditService auditService = Globals.getDefaultHabitat().getService(AdminAuditService.class); + if (auditService != null && auditService.isEnabled()) { + auditService.recordAsadminCommand(commandName, parameters, subject); + } CommandRunner cr = Globals.getDefaultHabitat().getService(CommandRunner.class); RestActionReporter ar = new RestActionReporter(); - final CommandInvocation commandInvocation = - cr.getCommandInvocation(commandName, ar, subject); + final CommandInvocation commandInvocation = cr.getCommandInvocation(commandName, ar, subject); if (managedJob) { commandInvocation.managedJob(); } diff --git a/nucleus/admin/rest/rest-service/src/test/java/fish/payara/admin/rest/utils/RunCommandTest.java b/nucleus/admin/rest/rest-service/src/test/java/fish/payara/admin/rest/utils/RunCommandTest.java new file mode 100644 index 00000000000..94fca945683 --- /dev/null +++ b/nucleus/admin/rest/rest-service/src/test/java/fish/payara/admin/rest/utils/RunCommandTest.java @@ -0,0 +1,365 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2019] Payara Foundation 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://github.com/payara/Payara/blob/master/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. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation 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. + */ +package fish.payara.admin.rest.utils; + +import java.io.BufferedReader; +import java.util.ArrayList; +import java.util.LinkedList; +import java.util.List; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.inject.Inject; + +import javax.security.auth.Subject; + +import com.sun.enterprise.v3.common.DoNothingActionReporter; + +import fish.payara.audit.AdminAuditConfiguration; +import fish.payara.audit.AdminAuditService; +import fish.payara.audit.admin.GetAdminAuditServiceConfiguration; +import fish.payara.nucleus.notification.NotificationService; +import fish.payara.nucleus.notification.configuration.Notifier; +import fish.payara.nucleus.notification.configuration.NotifierType; +import fish.payara.nucleus.notification.domain.EventSource; +import fish.payara.nucleus.notification.domain.NotificationEvent; +import fish.payara.nucleus.notification.domain.NotifierExecutionOptionsFactoryStore; +import fish.payara.nucleus.notification.log.LogNotificationEvent; +import fish.payara.nucleus.notification.service.NotificationEventFactoryStore; +import java.beans.PropertyVetoException; + + +import org.glassfish.admin.rest.utils.ResourceUtil; +import org.glassfish.admin.rest.utils.xml.RestActionReporter; +import org.glassfish.api.ActionReport; +import org.glassfish.api.StartupRunLevel; +import org.glassfish.api.admin.AdminCommand; +import org.glassfish.api.admin.AdminCommandEventBroker; +import org.glassfish.api.admin.CommandModel; +import org.glassfish.api.admin.CommandParameters; +import org.glassfish.api.admin.CommandRunner; +import org.glassfish.api.admin.ParameterMap; +import org.glassfish.api.admin.Payload; +import org.glassfish.api.admin.ProgressStatus; + +import org.jvnet.hk2.config.ConfigBeanProxy; +import org.jvnet.hk2.config.TransactionFailure; +import org.glassfish.hk2.api.DynamicConfiguration; +import org.glassfish.hk2.api.DynamicConfigurationService; +import org.glassfish.hk2.api.ServiceLocator; +import org.glassfish.hk2.api.ServiceLocatorFactory; +import org.glassfish.hk2.runlevel.RunLevelContext; +import org.glassfish.hk2.runlevel.RunLevelController; +import org.glassfish.hk2.runlevel.internal.AsyncRunLevelContext; +import org.glassfish.hk2.runlevel.internal.RunLevelControllerImpl; +import org.glassfish.hk2.utilities.ServiceLocatorUtilities; +import org.glassfish.internal.api.Globals; +import org.glassfish.internal.api.Target; + +import org.junit.Before; +import org.junit.Test; +import org.jvnet.hk2.annotations.ContractsProvided; +import org.jvnet.hk2.annotations.Service; +import org.testng.Assert; + +import sun.security.acl.PrincipalImpl; + +/** + * Test for running a command to check that is is processed properly. + * This tests the admin audit service. + * @see ResourceUtil#runCommand(java.lang.String, org.glassfish.api.admin.ParameterMap, javax.security.auth.Subject) + * @author jonathan coustick + */ +public class RunCommandTest { + + private ServiceLocator serviceLocator; + + private List events; + + @Before + public void setUp() { + serviceLocator = ServiceLocatorFactory.getInstance().create("testServiceLocator"); + ServiceLocatorUtilities.addOneConstant(serviceLocator, new TestNotificationService()); + ServiceLocatorUtilities.addOneConstant(serviceLocator, this); + ServiceLocatorUtilities.addClasses(serviceLocator, AdminAuditService.class, GetAdminAuditServiceConfiguration.class, TestConfiguration.class, + Target.class, NotificationEventFactoryStore.class, NotifierExecutionOptionsFactoryStore.class, TestCommandRunner.class); + + Globals.setDefaultHabitat(serviceLocator); + + DynamicConfigurationService dcs = serviceLocator.getService(DynamicConfigurationService.class); + DynamicConfiguration config = dcs.createDynamicConfiguration(); + + config.addActiveDescriptor(RunLevelControllerImpl.class); + config.addActiveDescriptor(AsyncRunLevelContext.class); + config.addActiveDescriptor(RunLevelContext.class); + + config.commit(); + + serviceLocator.getService(RunLevelController.class).proceedTo(StartupRunLevel.VAL); + serviceLocator.getService(NotificationEventFactoryStore.class).register(NotifierType.LOG, new fish.payara.nucleus.notification.log.LogNotificationEventFactory() { + @Override + public LogNotificationEvent buildNotificationEvent(Level level, String subject, String message, Object[] parameters) { + LogNotificationEvent event = new LogNotificationEvent(); + Assert.assertEquals(Level.WARNING, level); + event.setLevel(level); + Assert.assertNull(parameters); + event.setParameters(parameters); + event.setMessage(message); + Assert.assertEquals("AUDIT", subject); + event.setSubject(subject); + return event; + } + }); + + + events = new LinkedList<>(); + } + + @Test + public void testAdminAudit() { + Subject testSubject = new Subject(); + testSubject.getPrincipals().add(new PrincipalImpl("testuser")); + RestActionReporter commandResult = ResourceUtil.runCommand("get-admin-audit-configuration", new ParameterMap(), testSubject); + Assert.assertTrue(commandResult.isSuccess()); + + + } + + @Service + @ContractsProvided(NotificationService.class) + class TestNotificationService extends NotificationService { + + @Override + public void notify(EventSource source, NotificationEvent notificationEvent) { + if (!source.equals(EventSource.AUDIT)) { + Assert.fail("Recieved non-audit message, was of type" + source.getValue()); + } + events.add(notificationEvent); + + } + + } + + @Service + @ContractsProvided(AdminAuditConfiguration.class) + class TestConfiguration implements AdminAuditConfiguration { + + @Inject + public TestConfiguration() { + + } + + + @Override + public String getEnabled() { + return Boolean.TRUE.toString(); + } + + @Override + public void enabled(String value) throws PropertyVetoException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public String getAuditLevel() { + return "INTERNAL"; + } + + @Override + public void setAuditLevel(String value) throws PropertyVetoException { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public List getNotifierList() { + return new ArrayList<>(); + } + + @Override + public T getNotifierByType(Class type) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public ConfigBeanProxy getParent() { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public T getParent(Class type) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public T createChild(Class type) throws TransactionFailure { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public ConfigBeanProxy deepCopy(ConfigBeanProxy parent) throws TransactionFailure { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + } + + @Service + @ContractsProvided(CommandRunner.class) + class TestCommandRunner implements CommandRunner { + + @Inject + public TestCommandRunner() { + + } + + @Override + public ActionReport getActionReport(String name) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public CommandModel getModel(String name, Logger logger) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public CommandModel getModel(String scope, String name, Logger logger) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public BufferedReader getHelp(CommandModel model) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean validateCommandModelETag(AdminCommand command, String eTag) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public boolean validateCommandModelETag(CommandModel model, String eTag) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public AdminCommand getCommand(String commandName, ActionReport report, Logger logger) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public AdminCommand getCommand(String scope, String commandName, ActionReport report, Logger logger) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public CommandInvocation getCommandInvocation(String name, ActionReport report, Subject subject) { + return new CommandInvocation() { + @Override + public CommandInvocation parameters(CommandParameters params) { + return this; + } + + @Override + public CommandInvocation parameters(ParameterMap params) { + return this; + } + + @Override + public CommandInvocation inbound(Payload.Inbound inbound) { + return this; + } + + @Override + public CommandInvocation outbound(Payload.Outbound outbound) { + return this; + } + + @Override + public CommandInvocation listener(String nameRegexp, AdminCommandEventBroker.AdminCommandListener listener) { + return this; + } + + @Override + public CommandInvocation progressStatusChild(ProgressStatus ps) { + return this; + } + + @Override + public CommandInvocation managedJob() { + return this; + } + + @Override + public ActionReport report() { + return new DoNothingActionReporter(); + } + + @Override + public void execute() { + // do nothing + } + + @Override + public void execute(AdminCommand command) { + //do nothing + } + }; + } + + @Override + public CommandInvocation getCommandInvocation(String scope, String name, ActionReport report, Subject subject) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public CommandInvocation getCommandInvocation(String name, ActionReport report, Subject subject, boolean isNotify) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + @Override + public CommandInvocation getCommandInvocation(String scope, String name, ActionReport report, Subject subject, boolean isNotify) { + throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates. + } + + } + +} diff --git a/nucleus/packager/asadmin-recorder-package/pom.xml b/nucleus/packager/asadmin-recorder-package/pom.xml index 358b209f932..7e6caed0db0 100644 --- a/nucleus/packager/asadmin-recorder-package/pom.xml +++ b/nucleus/packager/asadmin-recorder-package/pom.xml @@ -1,22 +1,43 @@ + 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. +--> 4.0.0 @@ -29,7 +50,7 @@ asadmin-recorder-package Nucleus Payara Asadmin Recorder Package distribution-fragment - This pom describes how to assemble the Nucleus Payara Asadmin Recorder package + This pom describes how to assemble the Nucleus Payara Asadmin Recorder and Audit package @@ -37,6 +58,11 @@ asadmin-recorder ${project.version} + + fish.payara.payara-modules + asadmin-audit + ${project.version} + diff --git a/nucleus/payara-modules/asadmin-audit/pom.xml b/nucleus/payara-modules/asadmin-audit/pom.xml new file mode 100644 index 00000000000..4469c8542c7 --- /dev/null +++ b/nucleus/payara-modules/asadmin-audit/pom.xml @@ -0,0 +1,74 @@ + + + + 4.0.0 + + fish.payara.payara-modules + payara-nucleus-modules + 5.192-SNAPSHOT + ../pom.xml + + asadmin-audit + glassfish-jar + Payara Asadmin Auditor + + + + org.glassfish.hk2 + hk2-core + + + org.glassfish.main.common + glassfish-api + ${project.version} + + + org.glassfish.main.common + internal-api + ${project.version} + + + fish.payara.payara-modules + notification-core + ${project.version} + + + diff --git a/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/AdminAuditConfiguration.java b/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/AdminAuditConfiguration.java new file mode 100644 index 00000000000..bf429dc466c --- /dev/null +++ b/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/AdminAuditConfiguration.java @@ -0,0 +1,94 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2019] Payara Foundation 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://github.com/payara/Payara/blob/master/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. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation 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. + */ +package fish.payara.audit; + +import fish.payara.nucleus.notification.configuration.Notifier; + +import java.beans.PropertyVetoException; +import java.util.List; +import javax.validation.constraints.Pattern; + +import org.glassfish.api.admin.config.ConfigExtension; +import org.jvnet.hk2.config.Attribute; +import org.jvnet.hk2.config.ConfigBeanProxy; +import org.jvnet.hk2.config.Configured; +import org.jvnet.hk2.config.DuckTyped; +import org.jvnet.hk2.config.Element; + +/** + * Configuration for the Admin Audit service + * @author jonathan coustick + */ +@Configured +public interface AdminAuditConfiguration extends ConfigBeanProxy, ConfigExtension { + + @Attribute(defaultValue="false",dataType=Boolean.class) + String getEnabled(); + void enabled(String value) throws PropertyVetoException; + + @Attribute(defaultValue="MODIFIERS") + @Pattern(regexp = "MODIFIERS|ACCESSORS|INTERNAL", message = "Invalid audit level. Value must be one of: MODIFIERS, ACCESSORS or INTERNAL.") + String getAuditLevel(); + void setAuditLevel(String value) throws PropertyVetoException; + + @Element("*") + List getNotifierList(); + + @DuckTyped + T getNotifierByType(Class type); + + class Duck { + public static T getNotifierByType(AdminAuditConfiguration config, Class type) { + for (Notifier notifier : config.getNotifierList()) { + try { + return type.cast(notifier); + } catch (Exception e) { + // ignore, not the right type. + } + } + return null; + } + + } + +} diff --git a/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/AdminAuditService.java b/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/AdminAuditService.java new file mode 100644 index 00000000000..f7a803f471d --- /dev/null +++ b/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/AdminAuditService.java @@ -0,0 +1,203 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2019] Payara Foundation 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://github.com/payara/Payara/blob/master/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. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation 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. + */ +package fish.payara.audit; + +import fish.payara.nucleus.notification.NotificationService; +import fish.payara.nucleus.notification.configuration.Notifier; +import fish.payara.nucleus.notification.configuration.NotifierConfigurationType; +import fish.payara.nucleus.notification.domain.EventSource; +import fish.payara.nucleus.notification.domain.NotificationEvent; +import fish.payara.nucleus.notification.domain.NotificationEventFactory; +import fish.payara.nucleus.notification.domain.NotifierExecutionOptions; +import fish.payara.nucleus.notification.domain.NotifierExecutionOptionsFactory; +import fish.payara.nucleus.notification.domain.NotifierExecutionOptionsFactoryStore; +import fish.payara.nucleus.notification.log.LogNotifierExecutionOptions; +import fish.payara.nucleus.notification.service.NotificationEventFactoryStore; +import java.security.Principal; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Set; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import javax.security.auth.Subject; +import org.glassfish.api.StartupRunLevel; +import org.glassfish.api.admin.ParameterMap; +import org.glassfish.hk2.runlevel.RunLevel; +import org.jvnet.hk2.annotations.Service; +import org.jvnet.hk2.config.ConfigSupport; +import org.jvnet.hk2.config.ConfigView; + +/** + * Audit Admin commands and sends them to the notification services. + * + * Currently only for commands sent via the admin console. + * @author jonathan coustick + * @since 5.192 + */ +@Service(name = "asadmin-audit") +@RunLevel(StartupRunLevel.VAL) +public class AdminAuditService { + + private static final String AUDIT_MESSAGE = "AUDIT"; + private static final List ACCESSOR_COMMAND_START = Arrays.asList("_", "get", "list", "help", "version"); + + private boolean enabled; + private AuditLevel auditLevel = AuditLevel.MODIFIERS; + + @Inject + NotificationService notificationSevice; + + @Inject + private NotificationEventFactoryStore eventFactoryStore; + + @Inject + private NotifierExecutionOptionsFactoryStore executionOptionsFactoryStore; + + @Inject + AdminAuditConfiguration configuration; + + + private List notifierExecutionOptionsList; + + @PostConstruct + public void postConstruct() { + enabled = Boolean.valueOf(configuration.getEnabled()); + auditLevel = AuditLevel.valueOf(configuration.getAuditLevel()); + if (enabled) { + bootstrapNotifierList(); + } + } + + public boolean isEnabled() { + return enabled; + } + + public void setEnabled(Boolean enabled) { + if (!this.enabled && enabled) { + Logger.getLogger("fish.payara.audit").log(Level.INFO, "Admin Audit Service Started"); + bootstrapNotifierList(); + } + this.enabled = enabled; + } + + public AuditLevel getAuditLevel() { + return auditLevel; + } + + public void setAuditLevel(AuditLevel level){ + auditLevel = level; + } + + /** + * Starts all notifiers that have been enable with the admin audit service. + */ + public synchronized void bootstrapNotifierList() { + notifierExecutionOptionsList = new ArrayList<>(); + if (configuration.getNotifierList() != null) { + for (Notifier notifier : configuration.getNotifierList()) { + ConfigView view = ConfigSupport.getImpl(notifier); + NotifierConfigurationType annotation = view.getProxyType().getAnnotation(NotifierConfigurationType.class); + NotifierExecutionOptionsFactory factory = executionOptionsFactoryStore.get(annotation.type()); + if (factory != null) { + notifierExecutionOptionsList.add(factory.build(notifier)); + } + } + } + if (notifierExecutionOptionsList.isEmpty()) { + // Add logging execution options by default + LogNotifierExecutionOptions logNotifierExecutionOptions = new LogNotifierExecutionOptions(); + logNotifierExecutionOptions.setEnabled(true); + notifierExecutionOptionsList.add(logNotifierExecutionOptions); + } + } + + /** + * Gets a list of all the options of all notifiers configured with the asadmin audit service. + * @return + */ + public List getNotifierExecutionOptionsList() { + return notifierExecutionOptionsList; + } + + + public void recordAsadminCommand(String command, ParameterMap parameters, Subject subject) { + if (enabled && notifierExecutionOptionsList != null && checkAuditLevel(command)) { + + Set principals = subject.getPrincipals(); + String name = principals.iterator().next().getName(); + for (NotifierExecutionOptions notifierExecutionOptions : notifierExecutionOptionsList) { + + if (notifierExecutionOptions.isEnabled()) { + NotificationEventFactory notificationEventFactory = eventFactoryStore.get(notifierExecutionOptions.getNotifierType()); + NotificationEvent notificationEvent = notificationEventFactory + .buildNotificationEvent(Level.WARNING, AUDIT_MESSAGE, name + " issued command " + command + " with parameters " + parameters.toString(), null); + notificationSevice.notify(EventSource.AUDIT, notificationEvent); + } + } + } + } + + private boolean checkAuditLevel(String command) { + switch (auditLevel) { + case INTERNAL: + return true; + case ACCESSORS: + if (!command.startsWith("_")) { + return true; + } + break; + default: + for (String start: ACCESSOR_COMMAND_START) { + if (command.startsWith(start)) { + return false; + } + } + return true; + } + return false; + } + +} diff --git a/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/AuditLevel.java b/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/AuditLevel.java new file mode 100644 index 00000000000..99025f15b0e --- /dev/null +++ b/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/AuditLevel.java @@ -0,0 +1,80 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2019] Payara Foundation 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://github.com/payara/Payara/blob/master/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. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation 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. + */ +package fish.payara.audit; + +/** + * An enum for the levels of audit logging + * @author jonathan coustick + * @since 5.192 + */ +public enum AuditLevel { + + /** + * Admin commands that change + */ + MODIFIERS("Modifiers"), + /** + * {@code Modifiers} plus commands that retrieve information + */ + ACCESSORS("Accessors"), + /** + * All admin commands, including internal ones + */ + INTERNAL("Internal"); + + private final String value; + + AuditLevel(String value) { + this.value = value; + } + + /** + * Gets a {@link String} representation of the value + * of the enum. + * @return value + */ + public String getValue() { + return value; + } + +} diff --git a/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/admin/GetAdminAuditServiceConfiguration.java b/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/admin/GetAdminAuditServiceConfiguration.java new file mode 100644 index 00000000000..37ff066d548 --- /dev/null +++ b/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/admin/GetAdminAuditServiceConfiguration.java @@ -0,0 +1,180 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2019] Payara Foundation 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://github.com/payara/Payara/blob/master/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. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation 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. + */ +package fish.payara.audit.admin; + +import com.google.common.base.Function; +import com.google.common.collect.Lists; +import com.sun.enterprise.config.serverbeans.Config; +import com.sun.enterprise.util.ColumnFormatter; +import com.sun.enterprise.util.SystemPropertyConstants; +import fish.payara.audit.AdminAuditConfiguration; +import fish.payara.nucleus.notification.configuration.Notifier; +import fish.payara.nucleus.notification.configuration.NotifierConfigurationType; +import fish.payara.nucleus.notification.service.BaseNotifierService; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import javax.inject.Inject; +import org.glassfish.api.ActionReport; +import org.glassfish.api.Param; +import org.glassfish.api.admin.AdminCommand; +import org.glassfish.api.admin.AdminCommandContext; +import org.glassfish.api.admin.CommandLock; +import org.glassfish.api.admin.ExecuteOn; +import org.glassfish.api.admin.RestEndpoint; +import org.glassfish.api.admin.RestEndpoints; +import org.glassfish.api.admin.RuntimeType; +import org.glassfish.config.support.CommandTarget; +import org.glassfish.config.support.TargetType; +import org.glassfish.hk2.api.PerLookup; +import org.glassfish.hk2.api.ServiceHandle; +import org.glassfish.hk2.api.ServiceLocator; +import org.glassfish.internal.api.Target; +import org.jvnet.hk2.annotations.Service; +import org.jvnet.hk2.config.ConfigSupport; +import org.jvnet.hk2.config.ConfigView; + +/** + * Gets the current configuration of the admin audit service + * @author jonathan coustick + * @since 5.192 + */ +@Service(name = "get-admin-audit-configuration") +@PerLookup +@CommandLock(CommandLock.LockType.NONE) +@ExecuteOn({RuntimeType.DAS, RuntimeType.INSTANCE}) +@TargetType(value = {CommandTarget.DAS, CommandTarget.STANDALONE_INSTANCE, CommandTarget.CLUSTER, CommandTarget.CLUSTERED_INSTANCE, CommandTarget.CONFIG, + CommandTarget.DEPLOYMENT_GROUP}) +@RestEndpoints({ + @RestEndpoint(configBean = AdminAuditConfiguration.class, + opType = RestEndpoint.OpType.GET, + path = "get-admin-audit-configuration", + description = "Gets the current configuration settings of the admin audit Service") +}) +public class GetAdminAuditServiceConfiguration implements AdminCommand { + + private final static String[] ATTRIBUTE_HEADERS = {"Enabled", "Audit Level"}; + private final static String[] NOTIFIER_HEADERS= {"Name", "Notifier Enabled"}; + + @Inject + ServiceLocator serviceLocator; + + @Param(name = "target", optional = true, defaultValue = SystemPropertyConstants.DAS_SERVER_NAME) + private String target; + private Config targetConfig; + + @Inject + private Target targetUtil; + + @Override + public void execute(AdminCommandContext context) { + + final ActionReport actionReport = context.getActionReport(); + + ColumnFormatter columnFormatter = new ColumnFormatter(ATTRIBUTE_HEADERS); + ColumnFormatter notifiersColumnFormatter = new ColumnFormatter(NOTIFIER_HEADERS); + + targetConfig = targetUtil.getConfig(target); + AdminAuditConfiguration config = targetConfig.getExtensionByType(AdminAuditConfiguration.class); + + Object[] configValues = {config.getEnabled(), config.getAuditLevel()}; + columnFormatter.addRow(configValues); + + Map map = new HashMap<>(); + Properties extraProperties = new Properties(); + map.put("enabled", config.getEnabled()); + map.put("auditLevel", config.getAuditLevel()); + extraProperties.put("adminauditConfiguration", map); + + ActionReport notifiersReport = actionReport.addSubActionsReport(); + + List> allNotifierServiceHandles = serviceLocator.getAllServiceHandles(BaseNotifierService.class); + + Properties notifierProps = new Properties(); + if (!config.getNotifierList().isEmpty()) { + List> notifierClassList = Lists.transform(config.getNotifierList(), new Function>() { + @Override + public Class apply(Notifier input) { + return resolveNotifierClass(input); + } + }); + + for (ServiceHandle serviceHandle : allNotifierServiceHandles) { + Notifier notifier = config.getNotifierByType(serviceHandle.getService().getNotifierType()); + if (notifier != null) { + ConfigView view = ConfigSupport.getImpl(notifier); + NotifierConfigurationType annotation = view.getProxyType().getAnnotation(NotifierConfigurationType.class); + + if (notifierClassList.contains(view.getProxyType())) { + Object values[] = new Object[2]; + values[0] = annotation.type(); + values[1] = notifier.getEnabled(); + notifiersColumnFormatter.addRow(values); + + Map mapNotifiers = new HashMap<>(2); + mapNotifiers.put("notifierName", values[0]); + mapNotifiers.put("notifierEnabled", values[1]); + + notifierProps.put("notifierList" + annotation.type(), mapNotifiers); + } + } + + } + } + notifiersReport.setMessage(notifiersColumnFormatter.toString()); + extraProperties.put("notifiers", notifierProps); + + + actionReport.setExtraProperties(extraProperties); + + actionReport.setMessage(columnFormatter.toString()); + actionReport.setActionExitCode(ActionReport.ExitCode.SUCCESS); + } + + private Class resolveNotifierClass(Notifier input) { + ConfigView view = ConfigSupport.getImpl(input); + return view.getProxyType(); + } + +} diff --git a/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/admin/SetAdminAuditConfiguration.java b/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/admin/SetAdminAuditConfiguration.java new file mode 100644 index 00000000000..de1c97fc27c --- /dev/null +++ b/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/admin/SetAdminAuditConfiguration.java @@ -0,0 +1,145 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2019] Payara Foundation 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://github.com/payara/Payara/blob/master/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. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation 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. + */ +package fish.payara.audit.admin; + +import com.sun.enterprise.config.serverbeans.Config; +import com.sun.enterprise.util.SystemPropertyConstants; +import org.glassfish.api.Param; +import org.glassfish.api.admin.AdminCommand; +import org.glassfish.api.admin.AdminCommandContext; + +import fish.payara.audit.AuditLevel; +import fish.payara.audit.AdminAuditConfiguration; +import fish.payara.audit.AdminAuditService; +import java.beans.PropertyVetoException; +import java.util.logging.Level; +import java.util.logging.Logger; +import javax.inject.Inject; +import org.glassfish.api.ActionReport; +import org.glassfish.api.admin.ExecuteOn; +import org.glassfish.api.admin.RestEndpoint; +import org.glassfish.api.admin.RestEndpoints; +import org.glassfish.api.admin.RuntimeType; +import org.glassfish.config.support.CommandTarget; +import org.glassfish.config.support.TargetType; +import org.glassfish.hk2.api.PerLookup; +import org.glassfish.internal.api.Target; +import org.jvnet.hk2.annotations.Service; +import org.jvnet.hk2.config.ConfigSupport; +import org.jvnet.hk2.config.SingleConfigCode; +import org.jvnet.hk2.config.TransactionFailure; + +/** + * Sets the Admin Audit Configuration + * + * @author jonathan coustick + * @since 5.192 + */ +@Service(name = "set-admin-audit-configuration") +@PerLookup +@ExecuteOn({RuntimeType.DAS, RuntimeType.INSTANCE}) +@TargetType(value = {CommandTarget.DAS, CommandTarget.STANDALONE_INSTANCE, CommandTarget.CLUSTER, CommandTarget.CLUSTERED_INSTANCE, CommandTarget.CONFIG, + CommandTarget.DEPLOYMENT_GROUP}) +@RestEndpoints({ + @RestEndpoint(configBean = AdminAuditConfiguration.class, + opType = RestEndpoint.OpType.POST, + path = "set-admin-audit-configuration", + description = "Sets the Configuration for the Admin Audit Service") +}) +public class SetAdminAuditConfiguration implements AdminCommand { + + private static final Logger LOGGER = Logger.getLogger(SetAdminAuditConfiguration.class.getPackage().toString()); + + @Param(name = "dynamic", optional = true, defaultValue = "false") + private Boolean dynamic; + + @Param(name = "enabled") + private Boolean enabled; + + @Param(name = "auditLevel", optional = true, acceptableValues = "MODIFIERS, ACCESSORS, INTERNAL") + private String auditLevel; + + @Param(name = "target", optional = true, defaultValue = SystemPropertyConstants.DAS_SERVER_NAME) + private String target; + private Config targetConfig; + + @Inject + private AdminAuditService auditService; + + @Inject + private Target targetUtil; + + @Override + public void execute(AdminCommandContext context) { + ActionReport report = context.getActionReport(); + + targetConfig = targetUtil.getConfig(target); + + final AdminAuditConfiguration configuration = targetConfig.getExtensionByType(AdminAuditConfiguration.class); + + try { + ConfigSupport.apply(new SingleConfigCode() { + @Override + public Object run(AdminAuditConfiguration configurationProxy) throws PropertyVetoException, TransactionFailure { + + configurationProxy.enabled(enabled.toString()); + configurationProxy.setAuditLevel(auditLevel); + return null; + } + }, configuration); + + if (dynamic && target.equals("server-config")) { + auditService.setEnabled(enabled); + auditService.setAuditLevel(AuditLevel.valueOf(auditLevel)); + } + } catch (TransactionFailure ex) { + LOGGER.log(Level.SEVERE, null, ex); + report.setMessage(ex.getCause() != null ? ex.getCause().getMessage() : ex.getMessage()); + report.setActionExitCode(ActionReport.ExitCode.FAILURE); + } + + report.setActionExitCode(ActionReport.ExitCode.SUCCESS); + + } + +} diff --git a/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/admin/SetAdminAuditServiceNotifierConfiguration.java b/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/admin/SetAdminAuditServiceNotifierConfiguration.java new file mode 100644 index 00000000000..9cde0e4653a --- /dev/null +++ b/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/admin/SetAdminAuditServiceNotifierConfiguration.java @@ -0,0 +1,223 @@ +/* + * + * Copyright (c) 2019 Payara Foundation 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://github.com/payara/Payara/blob/master/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 glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation 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. + */ +package fish.payara.audit.admin; + +import java.beans.PropertyVetoException; +import java.lang.reflect.Proxy; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; +import java.util.logging.Level; +import java.util.logging.Logger; +import java.util.stream.Collectors; + +import javax.inject.Inject; + +import org.glassfish.api.ActionReport; +import org.glassfish.api.Param; +import org.glassfish.api.admin.AdminCommand; +import org.glassfish.api.admin.AdminCommandContext; +import org.glassfish.api.admin.ExecuteOn; +import org.glassfish.api.admin.RestEndpoint; +import org.glassfish.api.admin.RestEndpoints; +import org.glassfish.api.admin.RuntimeType; +import org.glassfish.api.admin.ServerEnvironment; +import org.glassfish.config.support.CommandTarget; +import org.glassfish.config.support.TargetType; +import org.glassfish.hk2.api.PerLookup; +import org.glassfish.internal.api.Target; +import org.jvnet.hk2.annotations.Service; +import org.jvnet.hk2.config.ConfigSupport; +import org.jvnet.hk2.config.SingleConfigCode; +import org.jvnet.hk2.config.TransactionFailure; + +import com.sun.enterprise.config.modularity.ConfigModularityUtils; +import com.sun.enterprise.config.serverbeans.Config; +import com.sun.enterprise.util.SystemPropertyConstants; + +import fish.payara.audit.AdminAuditConfiguration; +import fish.payara.audit.AdminAuditService; + +import fish.payara.nucleus.notification.configuration.NotificationServiceConfiguration; +import fish.payara.nucleus.notification.configuration.Notifier; +import fish.payara.nucleus.notification.configuration.NotifierConfiguration; +import fish.payara.nucleus.notification.configuration.NotifierConfigurationType; +import fish.payara.nucleus.notification.configuration.NotifierType; + +/** + * Admin command to set enabled and noisy flags for a specific {@link Notifier} configuration as part of the + * {@link AdminAuditConfiguration}. + * + * This should not be confused with the {@link NotifierConfiguration} itself for that specific {@link Notifier} that + * exists as part of {@link NotificationServiceConfiguration}. + * + * When {@link #noisy} parameter is not specified the according {@link NotifierConfiguration} is loaded from the + * {@link NotificationServiceConfiguration} to use its {@link NotifierConfiguration#getNoisy()} as automatic fallback + * setting. + * + * @author jonathan coustick + * @since 5.192 + */ +@Service(name = "set-admin-audit-service-notifier-configuration") +@PerLookup +@ExecuteOn({RuntimeType.DAS, RuntimeType.INSTANCE}) +@TargetType(value ={CommandTarget.DEPLOYMENT_GROUP, CommandTarget.DAS, CommandTarget.STANDALONE_INSTANCE, CommandTarget.CLUSTER, + CommandTarget.CLUSTERED_INSTANCE, CommandTarget.CONFIG}) +@RestEndpoints({ + @RestEndpoint(configBean = AdminAuditConfiguration.class, + opType = RestEndpoint.OpType.POST, + path = "set-admin-audit-service-notifier-configuration", + description = "Sets the Configuration for specific Notifier for the Admin Audit Service") +}) +public class SetAdminAuditServiceNotifierConfiguration implements AdminCommand { + + @Param(name = "dynamic", optional = true, defaultValue = "false") + private Boolean dynamic; + + @Param(name = "target", optional = true, defaultValue = SystemPropertyConstants.DAS_SERVER_NAME) + private String target; + private Config targetConfig; + + @Param(name = "enabled") + private Boolean enabled; + + @Param(name = "noisy", optional = true) + private Boolean noisy; + + @Param(name = "notifier") + private String notifierName; + private NotifierType notifierType; + + @Inject + private Target targetUtil; + + @Inject + private ServerEnvironment server; + + @Inject + private ConfigModularityUtils configModularityUtils; + + @Inject + private AdminAuditService auditService; + + private ActionReport report; + + private static final Logger LOGGER = Logger.getLogger(SetAdminAuditServiceNotifierConfiguration.class.getPackage().toString()); + + @Override + public void execute(AdminCommandContext context) { + report = context.getActionReport(); + Properties extraProperties = report.getExtraProperties(); + if (extraProperties == null) { + extraProperties = new Properties(); + report.setExtraProperties(extraProperties); + } + try { + notifierType = NotifierType.valueOf(notifierName.toUpperCase()); + } catch (IllegalArgumentException e) { + String values = Arrays.asList(NotifierType.values()) + .stream().map(t -> t.name().toLowerCase()).collect(Collectors.joining(",")); + report.setMessage("Unknown notifier `" + notifierName + "`. Known are: " + values); + report.setActionExitCode(ActionReport.ExitCode.FAILURE); + return; + } + targetConfig = targetUtil.getConfig(target); + + final AdminAuditConfiguration config = targetConfig.getExtensionByType(AdminAuditConfiguration.class); + final Notifier notifier = selectByType(Notifier.class, config.getNotifierList()); + try { + if (notifier == null) { + ConfigSupport.apply((SingleConfigCode) configProxy -> { + @SuppressWarnings("unchecked") + Notifier newNotifier = configProxy.createChild(selectByType(Class.class, configModularityUtils.getInstalledExtensions(Notifier.class))); + configProxy.getNotifierList().add(newNotifier); + applyValues(newNotifier); + return configProxy; + }, config); + } else { + ConfigSupport.apply(notifierProxy -> { + applyValues(notifierProxy); + return notifierProxy; + }, notifier); + } + } catch (TransactionFailure ex) { + LOGGER.log(Level.WARNING, "Exception during command ", ex); + report.setMessage(ex.getCause() != null ? ex.getCause().getMessage() : ex.getMessage()); + report.setActionExitCode(ActionReport.ExitCode.FAILURE); + } + } + + private void applyValues(Notifier notifier) throws PropertyVetoException { + if (Boolean.parseBoolean(notifier.getEnabled()) != enabled) { + report.appendMessage(notifierName + ".enabled was " + notifier.getEnabled() + " set to " + enabled + "\n"); + notifier.enabled(enabled); + } + if (this.noisy == null) { + // inherit setting from the notifier's configuration + NotifierConfiguration config = selectByType(NotifierConfiguration.class, targetConfig + .getExtensionByType(NotificationServiceConfiguration.class).getNotifierConfigurationList()); + if (config != null) { + noisy = "true".equalsIgnoreCase("" + config.getNoisy()); + } + } + if (noisy != null && Boolean.parseBoolean(notifier.getNoisy()) != noisy) { + report.appendMessage(notifierName + ".noisy was " + notifier.getNoisy() + " set to " + noisy + "\n"); + notifier.noisy(noisy); + } + report.setActionExitCode(ActionReport.ExitCode.SUCCESS); + } + + private T selectByType(Class commonInterface, List candidates) { + for (T candidate : candidates) { + Class annotatedType = candidate instanceof Class ? (Class) candidate : candidate.getClass(); + if (Proxy.isProxyClass(annotatedType)) { + for (Class i : annotatedType.getInterfaces()) { + if (commonInterface.isAssignableFrom(i)) { + annotatedType = i; + } + } + } + NotifierConfigurationType type = annotatedType.getAnnotation(NotifierConfigurationType.class); + if (type != null && type.type() == notifierType) { + return candidate; + } + } + return null; + } +} diff --git a/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/package-info.java b/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/package-info.java new file mode 100644 index 00000000000..169c3d4b0cc --- /dev/null +++ b/nucleus/payara-modules/asadmin-audit/src/main/java/fish/payara/audit/package-info.java @@ -0,0 +1,49 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright (c) [2019] Payara Foundation 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://github.com/payara/Payara/blob/master/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. + * + * When distributing the software, include this License Header Notice in each + * file and include the License file at glassfish/legal/LICENSE.txt. + * + * GPL Classpath Exception: + * The Payara Foundation designates this particular file as subject to the "Classpath" + * exception as provided by the Payara Foundation 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. + */ + +/** + * Audit system for the admin console and rest management interface + * @since 5.192 + * @author Jonathan Coustick + */ +package fish.payara.audit; diff --git a/nucleus/payara-modules/notification-core/src/main/java/fish/payara/nucleus/notification/domain/EventSource.java b/nucleus/payara-modules/notification-core/src/main/java/fish/payara/nucleus/notification/domain/EventSource.java index a154955cdb9..04639548876 100644 --- a/nucleus/payara-modules/notification-core/src/main/java/fish/payara/nucleus/notification/domain/EventSource.java +++ b/nucleus/payara-modules/notification-core/src/main/java/fish/payara/nucleus/notification/domain/EventSource.java @@ -1,6 +1,6 @@ /* * - * Copyright (c) 2017 Payara Foundation and/or its affiliates. All rights reserved. + * Copyright (c) 2017-2019 Payara Foundation 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 @@ -44,7 +44,8 @@ public enum EventSource { HEALTHCHECK("HealthCheck"), REQUESTTRACING("RequestTracing"), - MONITORING("Monitoring"); + MONITORING("Monitoring"), + AUDIT("Audit"); private final String value; diff --git a/nucleus/payara-modules/notification-core/src/main/java/fish/payara/nucleus/notification/domain/NotificationEventFactory.java b/nucleus/payara-modules/notification-core/src/main/java/fish/payara/nucleus/notification/domain/NotificationEventFactory.java index 792ed1d4c89..d3cca7dfefc 100644 --- a/nucleus/payara-modules/notification-core/src/main/java/fish/payara/nucleus/notification/domain/NotificationEventFactory.java +++ b/nucleus/payara-modules/notification-core/src/main/java/fish/payara/nucleus/notification/domain/NotificationEventFactory.java @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright (c) 2016-2018 Payara Foundation and/or its affiliates. All rights reserved. + * Copyright (c) 2016-2019 Payara Foundation 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 @@ -56,7 +56,9 @@ import java.util.logging.Level; /** + * Factory for building {@link NotificationEvent} * @author mertcaliskan + * @since 4.1.2.171 */ @Contract public abstract class NotificationEventFactory { @@ -90,6 +92,13 @@ protected E initializeEvent(E e) { protected abstract E createEventInstance(); + /** + * Creates a {@link NotificationEvent} + * @param subject Subject of the message + * i.e. what the subject line is if the event is sent to the Javamail notifier + * @param message The message text of the event + * @return the resulting {@link NotificationEvent} + */ public E buildNotificationEvent(String subject, String message) { E event = initializeEvent(createEventInstance()); event.setSubject(subject); @@ -117,6 +126,15 @@ public E buildNotificationEvent(String name, List entrie return event; } + /** + * Creates a {@link NotificationEvent} + * @param level Severity level of notification. This is unused in the base factory + * @param subject Subject of the message + * i.e. what the subject line is if the event is sent to the Javamail notifier + * @param message The message text of the event + * @param parameters An additional parameters to be formatted as part of the message + * @return the resulting {@link NotificationEvent} + */ public E buildNotificationEvent(Level level, String subject, String message, Object[] parameters) { E event = initializeEvent(createEventInstance()); event.setSubject(subject); diff --git a/nucleus/payara-modules/pom.xml b/nucleus/payara-modules/pom.xml index 132c64e050d..0e2903f9654 100755 --- a/nucleus/payara-modules/pom.xml +++ b/nucleus/payara-modules/pom.xml @@ -2,7 +2,7 @@