From 40d140c94a4cedfb2e4ea6511d9bcf74cae7fac4 Mon Sep 17 00:00:00 2001 From: Gaurav Gupta Date: Fri, 20 Sep 2019 13:24:39 +0530 Subject: [PATCH 01/15] PAYARA-3658 ejb-invoker endpoint BASIC_AUTH security support --- appserver/ejb/ejb-http-remoting/admin/pom.xml | 10 + .../fish/payara/ejb/http/admin/Constants.java | 57 ++++ .../http/admin/DisableEjbInvokerCommand.java | 1 + .../http/admin/EjbInvokerConfiguration.java | 121 +++++++ .../admin/EjbInvokerContainerInitializer.java | 87 +++++ .../ejb/http/admin/EjbInvokerService.java | 97 ++++++ .../http/admin/EnableEjbInvokerCommand.java | 1 + .../GetEjbInvokerConfigurationCommand.java | 133 ++++++++ .../SetEjbInvokerConfigurationCommand.java | 304 ++++++++++++++++++ .../javax.servlet.ServletContainerInitializer | 1 + .../fish/payara/ejb/http/client/Lookup.java | 2 +- .../ejb/http/client/RemoteEJBContext.java | 23 +- .../http/client/RemoteEJBContextFactory.java | 6 + .../ejb/http/protocol/rs/BasicAuthFilter.java | 70 ++++ .../http/endpoint/EjbOverHttpResource.java | 4 - 15 files changed, 906 insertions(+), 11 deletions(-) create mode 100644 appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/Constants.java create mode 100644 appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerConfiguration.java create mode 100644 appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerContainerInitializer.java create mode 100644 appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerService.java create mode 100644 appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/GetEjbInvokerConfigurationCommand.java create mode 100644 appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/SetEjbInvokerConfigurationCommand.java create mode 100644 appserver/ejb/ejb-http-remoting/admin/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer create mode 100644 appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/protocol/rs/BasicAuthFilter.java diff --git a/appserver/ejb/ejb-http-remoting/admin/pom.xml b/appserver/ejb/ejb-http-remoting/admin/pom.xml index b855a60447b..95dde51ebeb 100644 --- a/appserver/ejb/ejb-http-remoting/admin/pom.xml +++ b/appserver/ejb/ejb-http-remoting/admin/pom.xml @@ -73,5 +73,15 @@ javaee-api ${javaee.api.version} + + fish.payara.server.internal.deployment + dol + ${project.version} + + + fish.payara.server.internal.core + kernel + ${project.version} + diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/Constants.java b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/Constants.java new file mode 100644 index 00000000000..aefee4cee2b --- /dev/null +++ b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/Constants.java @@ -0,0 +1,57 @@ +/* + * 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 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.ejb.http.admin; + +/** + * + * @author Gaurav Gupta + */ +public interface Constants { + + String DEFAULT_USER_NAME = "invoker"; + + String DEFAULT_GROUP_NAME = "invoker"; + + String DEFAULT_ENDPOINT = "ejb-invoker"; + + String ENDPOINTS_DIR = "endpoints"; + + String EJB_INVOKER_APP = "ejb-invoker"; +} diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/DisableEjbInvokerCommand.java b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/DisableEjbInvokerCommand.java index 71a1790887b..830802b9c44 100644 --- a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/DisableEjbInvokerCommand.java +++ b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/DisableEjbInvokerCommand.java @@ -78,6 +78,7 @@ * @author Arjan Tijms * */ +@Deprecated @Service(name = "disable-ejb-invoker") @PerLookup @ExecuteOn(RuntimeType.DAS) diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerConfiguration.java b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerConfiguration.java new file mode 100644 index 00000000000..b51d91653a3 --- /dev/null +++ b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerConfiguration.java @@ -0,0 +1,121 @@ +/* + * 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 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.ejb.http.admin; + +import static fish.payara.ejb.http.admin.Constants.DEFAULT_ENDPOINT; +import static fish.payara.ejb.http.admin.Constants.DEFAULT_GROUP_NAME; +import java.beans.PropertyVetoException; +import static javax.servlet.http.HttpServletRequest.BASIC_AUTH; +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; + +/** + * Configuration for the EJB Invoker Service. + * + * @author Gaurav Gupta + */ +@Configured(name = "ejb-invoker-configuration") +public interface EjbInvokerConfiguration extends ConfigBeanProxy, ConfigExtension { + + /** + * @return a Boolean value determining if the ejb-invoker service is enabled + * or disabled. + */ + @Attribute(defaultValue = "false", dataType = Boolean.class) + String getEnabled(); + + void setEnabled(String value) throws PropertyVetoException; + + /** + * @return a String value defines the endpoint of ejb-invoker service. + */ + @Attribute(defaultValue = DEFAULT_ENDPOINT) + String getEndpoint(); + + void setEndpoint(String value) throws PropertyVetoException; + + /** + * @return a String value defines the attached virtual servers. + */ + @Attribute(dataType = String.class) + String getVirtualServers(); + + void setVirtualServers(String value) throws PropertyVetoException; + + /** + * @return a Boolean value determining if the security is enabled or not. + */ + @Attribute(defaultValue = "false", dataType = Boolean.class) + String getSecurityEnabled(); + + void setSecurityEnabled(String value) throws PropertyVetoException; + + /** + * @return a String value defines the realm name. + * + * By default, file realm is used as default value fetched from + * {@code com.sun.enterprise.config.serverbeans.SecurityService#getDefaultRealm}. + */ + @Attribute(dataType = String.class) + String getRealmName(); + + void setRealmName(String value) throws PropertyVetoException; + + /** + * @return a String value defines the name of the authentication mechanism + * used to protect the ejb-invoker endpoint. + */ + @Attribute(defaultValue = BASIC_AUTH, dataType = String.class) + String getAuthType(); + + void setAuthType(String value) throws PropertyVetoException; + + /** + * @return a String value defines the roles. + */ + @Attribute(defaultValue = DEFAULT_GROUP_NAME, dataType = String.class) + String getRoles(); + + void setRoles(String value) throws PropertyVetoException; + +} diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerContainerInitializer.java b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerContainerInitializer.java new file mode 100644 index 00000000000..0691a26849e --- /dev/null +++ b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerContainerInitializer.java @@ -0,0 +1,87 @@ +/* + * 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 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.ejb.http.admin; + +import java.util.Set; +import javax.servlet.HttpConstraintElement; +import javax.servlet.ServletContainerInitializer; +import javax.servlet.ServletContext; +import javax.servlet.ServletException; +import javax.servlet.ServletRegistration; +import javax.servlet.ServletSecurityElement; +import static javax.servlet.annotation.ServletSecurity.TransportGuarantee.NONE; +import org.glassfish.internal.api.Globals; +import java.util.logging.Logger; + +/** + * + * @author Gaurav Gupta + */ +public class EjbInvokerContainerInitializer implements ServletContainerInitializer { + + private static final Logger LOGGER = Logger.getLogger(EjbInvokerContainerInitializer.class.getName()); + + @Override + public void onStartup(Set> set, ServletContext ctx) throws ServletException { + + EjbInvokerConfiguration configuration = Globals.getDefaultBaseServiceLocator() + .getService(EjbInvokerConfiguration.class); + String endpoint = ctx.getContextPath(); + if(endpoint.startsWith("/")){ + endpoint = endpoint.substring(1); + } + if (!configuration.getEndpoint().equals(endpoint)) { + return; + } + + if (Boolean.parseBoolean(configuration.getSecurityEnabled())) { + String[] roles = configuration.getRoles().split(","); + ServletRegistration.Dynamic reg = (ServletRegistration.Dynamic) ctx.getServletRegistration("fish.payara.ejb.http.endpoint.EjbOverHttpApplication"); + if (reg != null) { + reg.setServletSecurity(new ServletSecurityElement(new HttpConstraintElement(NONE, roles))); + } else { + LOGGER.warning("ejb-invoker endpoint not initialized"); + } + ctx.declareRoles(roles); + } + + } + +} diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerService.java b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerService.java new file mode 100644 index 00000000000..5855f633fdd --- /dev/null +++ b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerService.java @@ -0,0 +1,97 @@ +/* + * 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 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.ejb.http.admin; + +import com.sun.enterprise.config.serverbeans.SecurityService; +import com.sun.enterprise.deployment.Application; +import com.sun.enterprise.deployment.WebBundleDescriptor; +import com.sun.enterprise.deployment.web.LoginConfiguration; +import com.sun.enterprise.util.StringUtils; +import static fish.payara.ejb.http.admin.Constants.EJB_INVOKER_APP; +import javax.annotation.PostConstruct; +import javax.inject.Inject; +import org.glassfish.api.StartupRunLevel; +import org.glassfish.api.deployment.DeploymentContext; +import org.glassfish.api.event.EventListener; +import org.glassfish.api.event.Events; +import org.glassfish.hk2.runlevel.RunLevel; +import org.glassfish.internal.api.Globals; +import org.glassfish.internal.deployment.Deployment; +import org.jvnet.hk2.annotations.Service; +/** + * + * @author Gaurav Gupta + */ +@Service(name = "ejb-invoker-service") +@RunLevel(StartupRunLevel.VAL) +public class EjbInvokerService implements EventListener { + + @Inject + private Events events; + + @Inject + private SecurityService securityService; + + @Inject + private EjbInvokerConfiguration config; + + @PostConstruct + public void init() { + if (events == null) { + events = Globals.getDefaultBaseServiceLocator().getService(Events.class); + } + events.register(this); + } + + @Override + public void event(EventListener.Event event) {//event.type().type() + if (event.is(Deployment.APPLICATION_PREPARED)) { + DeploymentContext context = (DeploymentContext) event.hook(); + Application app = context.getModuleMetaData(Application.class); + if (EJB_INVOKER_APP.equals(app.getAppName())) { + for (WebBundleDescriptor descriptor : app.getBundleDescriptors(WebBundleDescriptor.class)) { + LoginConfiguration loginConf = descriptor.getLoginConfiguration(); + loginConf.setAuthenticationMethod(config.getAuthType()); + loginConf.setRealmName(StringUtils.ok(config.getRealmName()) ? config.getRealmName() : securityService.getDefaultRealm()); + } + } + } + } +} \ No newline at end of file diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EnableEjbInvokerCommand.java b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EnableEjbInvokerCommand.java index b6147212cec..62cac99a726 100644 --- a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EnableEjbInvokerCommand.java +++ b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EnableEjbInvokerCommand.java @@ -75,6 +75,7 @@ * @author Arjan Tijms * */ +@Deprecated @Service(name = "enable-ejb-invoker") @PerLookup @ExecuteOn(RuntimeType.DAS) diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/GetEjbInvokerConfigurationCommand.java b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/GetEjbInvokerConfigurationCommand.java new file mode 100644 index 00000000000..973f8ac5cca --- /dev/null +++ b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/GetEjbInvokerConfigurationCommand.java @@ -0,0 +1,133 @@ +/* + * 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 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.ejb.http.admin; + +import com.sun.enterprise.config.serverbeans.Config; +import com.sun.enterprise.util.ColumnFormatter; +import java.util.HashMap; +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.ExecuteOn; +import org.glassfish.api.admin.RestEndpoint; +import static org.glassfish.api.admin.RestEndpoint.OpType.GET; +import org.glassfish.api.admin.RestEndpoints; +import org.glassfish.api.admin.RuntimeType; +import static org.glassfish.config.support.CommandTarget.CLUSTER; +import static org.glassfish.config.support.CommandTarget.CLUSTERED_INSTANCE; +import static org.glassfish.config.support.CommandTarget.CONFIG; +import static org.glassfish.config.support.CommandTarget.DAS; +import static org.glassfish.config.support.CommandTarget.DEPLOYMENT_GROUP; +import static org.glassfish.config.support.CommandTarget.STANDALONE_INSTANCE; +import org.glassfish.config.support.TargetType; +import org.glassfish.hk2.api.PerLookup; +import org.glassfish.internal.api.Target; +import org.jvnet.hk2.annotations.Service; + +/** + * + * @author Gaurav Gupta + */ +@Service(name = "get-ejb-invoker-configuration") +@PerLookup +@ExecuteOn(RuntimeType.DAS) +@TargetType({CLUSTER, CLUSTERED_INSTANCE, CONFIG, DAS, DEPLOYMENT_GROUP, STANDALONE_INSTANCE}) +@RestEndpoints({ + @RestEndpoint(configBean = EjbInvokerConfiguration.class, + opType = GET, + path = "get-ejb-invoker-configuration", + description = "Gets the ejb-invoker configuration") +}) +public class GetEjbInvokerConfigurationCommand implements AdminCommand { + + private final String[] OUTPUT_HEADERS = {"Enabled", "EndPoint", "VirtualServers", "Security Enabled", "Realm Name", "Auth Type", "Roles"}; + + @Inject + private Target targetUtil; + + @Param(optional = true, defaultValue = "server-config") + public String target; + + @Override + public void execute(AdminCommandContext adminCommandContext) { + Config targetConfig = targetUtil.getConfig(target); + + if (targetConfig == null) { + adminCommandContext.getActionReport().setMessage("No such config name: " + targetUtil); + adminCommandContext.getActionReport().setActionExitCode(ActionReport.ExitCode.FAILURE); + return; + } + + EjbInvokerConfiguration configuration = targetConfig + .getExtensionByType(EjbInvokerConfiguration.class); + + ColumnFormatter columnFormatter = new ColumnFormatter(OUTPUT_HEADERS); + Object[] outputValues = { + configuration.getEnabled(), + configuration.getEndpoint(), + configuration.getVirtualServers(), + configuration.getSecurityEnabled(), + configuration.getRealmName(), + configuration.getAuthType(), + configuration.getRoles() + }; + columnFormatter.addRow(outputValues); + + adminCommandContext.getActionReport().appendMessage(columnFormatter.toString()); + + Map extraPropertiesMap = new HashMap<>(); + extraPropertiesMap.put("enabled", configuration.getEnabled()); + extraPropertiesMap.put("endpoint", configuration.getEndpoint()); + extraPropertiesMap.put("virtualServers", configuration.getVirtualServers()); + extraPropertiesMap.put("securityEnabled", configuration.getSecurityEnabled()); + extraPropertiesMap.put("realmName", configuration.getRealmName()); + extraPropertiesMap.put("authType", configuration.getAuthType()); + extraPropertiesMap.put("roles", configuration.getRoles()); + + Properties extraProperties = new Properties(); + extraProperties.put("ejbInvokerConfiguration", extraPropertiesMap); + adminCommandContext.getActionReport().setExtraProperties(extraProperties); + } + +} diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/SetEjbInvokerConfigurationCommand.java b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/SetEjbInvokerConfigurationCommand.java new file mode 100644 index 00000000000..e1ea88b3d6c --- /dev/null +++ b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/SetEjbInvokerConfigurationCommand.java @@ -0,0 +1,304 @@ +/* + * 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 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.ejb.http.admin; + +import com.sun.enterprise.config.serverbeans.Config; +import com.sun.enterprise.config.serverbeans.Domain; +import com.sun.enterprise.config.serverbeans.SecurityService; +import com.sun.enterprise.util.StringUtils; +import com.sun.enterprise.util.SystemPropertyConstants; +import static fish.payara.ejb.http.admin.Constants.DEFAULT_USER_NAME; +import static fish.payara.ejb.http.admin.Constants.EJB_INVOKER_APP; +import static fish.payara.ejb.http.admin.Constants.ENDPOINTS_DIR; +import java.nio.file.Path; +import java.util.logging.Logger; +import javax.inject.Inject; +import javax.security.auth.Subject; +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.CommandRunner; +import org.glassfish.api.admin.ExecuteOn; +import org.glassfish.api.admin.ParameterMap; +import org.glassfish.api.admin.RestEndpoint; +import static org.glassfish.api.admin.RestEndpoint.OpType.POST; +import org.glassfish.api.admin.RestEndpoints; +import org.glassfish.api.admin.RuntimeType; +import org.glassfish.api.admin.ServerEnvironment; +import static org.glassfish.config.support.CommandTarget.CLUSTER; +import static org.glassfish.config.support.CommandTarget.CLUSTERED_INSTANCE; +import static org.glassfish.config.support.CommandTarget.CONFIG; +import static org.glassfish.config.support.CommandTarget.DAS; +import static org.glassfish.config.support.CommandTarget.DEPLOYMENT_GROUP; +import static org.glassfish.config.support.CommandTarget.STANDALONE_INSTANCE; +import org.glassfish.config.support.TargetType; +import org.glassfish.deployment.autodeploy.AutoDeployer; +import static org.glassfish.deployment.autodeploy.AutoDeployer.getNameFromFilePath; +import org.glassfish.deployment.autodeploy.AutoDeploymentOperation; +import org.glassfish.deployment.autodeploy.AutoUndeploymentOperation; +import org.glassfish.hk2.api.PerLookup; +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.TransactionFailure; + +/** + * + * @author Gaurav Gupta + */ +@Service(name = "set-ejb-invoker-configuration") +@PerLookup +@ExecuteOn({RuntimeType.DAS}) +@TargetType({CLUSTER, CLUSTERED_INSTANCE, CONFIG, DAS, DEPLOYMENT_GROUP, STANDALONE_INSTANCE}) +@RestEndpoints({ + @RestEndpoint(configBean = EjbInvokerConfiguration.class, + opType = POST, + path = "set-ejb-invoker-configuration", + description = "Sets the ejb-invoker configuration") +}) +public class SetEjbInvokerConfigurationCommand implements AdminCommand { + + private static final Logger LOGGER = Logger.getLogger(SetEjbInvokerConfigurationCommand.class.getName()); + + @Inject + private Target targetUtil; + + @Param(optional = true) + private Boolean enabled; + + @Param(optional = true) + private String endpoint; + + @Param(optional = true, alias = "virtualservers") + private String virtualServers; + + @Param(optional = true, alias = "securityenabled") + protected Boolean securityEnabled; + + @Param(optional = true, alias = "realmname") + protected String realmName; + + @Param(optional = true, alias = "authtype") + protected String authType; + + @Param(optional = true) + protected String roles; + + @Param(optional = true, defaultValue = SystemPropertyConstants.DAS_SERVER_NAME) + protected String target; + + @Inject + protected CommandRunner commandRunner; + + @Inject + private SecurityService securityService; + + @Inject + private ServerEnvironment serverEnvironment; + + @Inject + private ServiceLocator serviceLocator; + + @Inject + private Domain domain; + + @Override + public void execute(AdminCommandContext context) { + ActionReport actionReport = context.getActionReport(); + Subject subject = context.getSubject(); + Config targetConfig = targetUtil.getConfig(target); + EjbInvokerConfiguration config = targetConfig.getExtensionByType(EjbInvokerConfiguration.class); + + try { + ConfigSupport.apply(configProxy -> { + if (enabled != null) { + configProxy.setEnabled(enabled.toString()); + } + if (endpoint != null) { + configProxy.setEndpoint(endpoint); + } + if (virtualServers != null) { + configProxy.setVirtualServers(virtualServers); + } + if (securityEnabled != null) { + configProxy.setSecurityEnabled(securityEnabled.toString()); + } + if (realmName != null) { + configProxy.setRealmName(realmName); + } + if (authType != null) { + configProxy.setAuthType(authType); + } + if (roles != null) { + configProxy.setRoles(roles); + } + actionReport.setActionExitCode(ActionReport.ExitCode.SUCCESS); + return configProxy; + }, config); + + } catch (TransactionFailure ex) { + actionReport.failure(LOGGER, "Failed to update EJB Invoker configuration", ex); + } + + if (Boolean.parseBoolean(config.getEnabled()) + && Boolean.parseBoolean(config.getSecurityEnabled())) { + // Create the default user if it doesn't exist + ActionReport checkUserReport = actionReport.addSubActionsReport(); + ActionReport createUserReport = actionReport.addSubActionsReport(); + if (!defaultUserExists(config, checkUserReport, subject) + && !checkUserReport.hasFailures()) { + createDefaultUser(config, createUserReport, subject); + } + if (checkUserReport.hasFailures() || createUserReport.hasFailures()) { + actionReport.setActionExitCode(ActionReport.ExitCode.FAILURE); + return; + } + } + + if (enabled != null) { + if (enabled) { + enableEjbInvoker(actionReport); + } else { + disableEjbInvoker(actionReport); + } + } + + // If everything has passed, scrap the subaction reports as we don't want to print them out + if (!actionReport.hasFailures() && !actionReport.hasWarnings()) { + actionReport.getSubActionsReport().clear(); + } + } + + + public void disableEjbInvoker(ActionReport report) { + Path endPointsPath = serverEnvironment.getInstanceRoot().toPath().resolve(ENDPOINTS_DIR); + Path ejbInvokerPath = endPointsPath.resolve(EJB_INVOKER_APP); + + AutoUndeploymentOperation autoUndeploymentOperation = AutoUndeploymentOperation.newInstance( + serviceLocator, + ejbInvokerPath.toFile(), + getNameFromFilePath(endPointsPath.toFile(), ejbInvokerPath.toFile()), + target); + + AutoDeployer.AutodeploymentStatus deploymentStatus = autoUndeploymentOperation.run(); + + report.setActionExitCode(deploymentStatus.getExitCode()); + + if (deploymentStatus.getExitCode().equals(ActionReport.ExitCode.FAILURE)) { + if (domain.getApplications().getApplication(EJB_INVOKER_APP) == null) { + report.appendMessage("\nEJB Invoker is not enabled on any target"); + } else { + report.appendMessage("\nFailed to disable Ejb Invoker - was it enabled on the specified target?"); + } + } + } + + public void enableEjbInvoker(ActionReport report) { + Path endPointsPath = serverEnvironment.getInstanceRoot().toPath().resolve(ENDPOINTS_DIR); + Path ejbInvokerPath = endPointsPath.resolve(EJB_INVOKER_APP); + Config targetConfig = targetUtil.getConfig(target); + EjbInvokerConfiguration configuration = targetConfig.getExtensionByType(EjbInvokerConfiguration.class); + + AutoDeploymentOperation autoDeploymentOperation = AutoDeploymentOperation.newInstance( + serviceLocator, + ejbInvokerPath.toFile(), + configuration.getVirtualServers(), + target, + configuration.getEndpoint() + ); + + if (domain.getApplications().getApplication(EJB_INVOKER_APP) == null) { + AutoDeployer.AutodeploymentStatus deploymentStatus = autoDeploymentOperation.run(); + report.setActionExitCode(deploymentStatus.getExitCode()); + } else { + report.setActionExitCode(ActionReport.ExitCode.WARNING); + report.setMessage("EJB Invoker is already deployed on at least one target, please edit it as you would a " + + "normal application using the create-application-ref, delete-application-ref, " + + "or update-application-ref commands"); + } + } + + protected boolean defaultUserExists(EjbInvokerConfiguration config, ActionReport subActionReport, Subject subject) { + CommandRunner.CommandInvocation invocation + = commandRunner.getCommandInvocation( + "list-file-users", + subActionReport, + subject, + false + ); + + ParameterMap parameters = new ParameterMap(); + parameters.add("authrealmname", + StringUtils.ok(config.getRealmName()) ? config.getRealmName() : securityService.getDefaultRealm()); + + invocation.parameters(parameters).execute(); + + for (ActionReport.MessagePart message : subActionReport.getTopMessagePart().getChildren()) { + if (message.getMessage().equals(DEFAULT_USER_NAME)) { + return true; + } + } + + return false; + } + + protected void createDefaultUser(EjbInvokerConfiguration config, ActionReport subActionReport, Subject subject) { + CommandRunner.CommandInvocation invocation + = commandRunner.getCommandInvocation( + "create-file-user", + subActionReport, + subject, + false + ); + + ParameterMap parameters = new ParameterMap(); + parameters.add("groups", config.getRoles().replace(',', ':')); + parameters.add("userpassword", DEFAULT_USER_NAME); + parameters.add("target", target); + parameters.add("authrealmname", + StringUtils.ok(config.getRealmName()) ? config.getRealmName() : securityService.getDefaultRealm()); + parameters.add("DEFAULT", DEFAULT_USER_NAME); + + invocation.parameters(parameters).execute(); + } + +} diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer b/appserver/ejb/ejb-http-remoting/admin/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer new file mode 100644 index 00000000000..d1ea39bd7ce --- /dev/null +++ b/appserver/ejb/ejb-http-remoting/admin/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer @@ -0,0 +1 @@ +fish.payara.ejb.http.admin.EjbInvokerContainerInitializer diff --git a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/Lookup.java b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/Lookup.java index 1a3fea08dbe..f3deedce060 100644 --- a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/Lookup.java +++ b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/Lookup.java @@ -45,7 +45,7 @@ import java.util.Base64; import java.util.Map; -abstract class Lookup { +public abstract class Lookup { protected final Map environment; protected Lookup(Map environment) { diff --git a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContext.java b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContext.java index 77cb4379534..1688b6c1799 100644 --- a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContext.java +++ b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContext.java @@ -1,7 +1,7 @@ /* * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. * - * Copyright (c) 2019 Payara Foundation and/or its affiliates. All rights reserved. + * 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 @@ -63,7 +63,10 @@ import java.util.logging.Logger; import static fish.payara.ejb.http.client.RemoteEJBContextFactory.*; +import fish.payara.ejb.http.protocol.rs.BasicAuthFilter; import static java.util.concurrent.TimeUnit.MICROSECONDS; +import java.util.logging.Level; +import static javax.ws.rs.core.SecurityContext.BASIC_AUTH; /** * This is the context used for looking up and invoking remote EJBs via @@ -166,11 +169,11 @@ private Lookup determineLookup(URI root) throws NamingException { Integer version = getVersion(discovery); if (discovery.isV1target() && (version == null || version.intValue() == 1)) { - logger.info("Discovered v1 at " + discovery.getV1lookup().getUri()); + logger.log(Level.INFO, "Discovered v1 at {0}", discovery.getV1lookup().getUri()); return new LookupV1(environment, client, discovery.getV1lookup()); } if (discovery.isV0target() && (version == null || version.intValue() == 0)) { - logger.info("Discovered v0 at " + discovery.getV0lookup().getUri()); + logger.log(Level.INFO, "Discovered v0 at {0}", discovery.getV0lookup().getUri()); return new LookupV0(environment, client.target(discovery.getResolvedRoot()), discovery.getV0lookup()); } throw new NamingException("EJB HTTP client V0 is not supported, out of ideas for now"); @@ -195,7 +198,7 @@ private ClientBuilder getClientBuilder() throws ClassNotFoundException, Instanti ClientBuilder clientBuilder = ClientBuilder.newBuilder(); if (environment.containsKey(JAXRS_CLIENT_CONNECT_TIMEOUT)) { - clientBuilder.connectTimeout(getLong(environment.get(JAXRS_CLIENT_CONNECT_TIMEOUT)).longValue(), MICROSECONDS); + clientBuilder.connectTimeout(getLong(environment.get(JAXRS_CLIENT_CONNECT_TIMEOUT)), MICROSECONDS); } if (environment.contains(JAXRS_CLIENT_EXECUTOR_SERVICE)) { @@ -211,7 +214,7 @@ private ClientBuilder getClientBuilder() throws ClassNotFoundException, Instanti } if (environment.containsKey(JAXRS_CLIENT_READ_TIMEOUT)) { - clientBuilder.readTimeout(getLong(environment.get(JAXRS_CLIENT_READ_TIMEOUT)).longValue(), MICROSECONDS); + clientBuilder.readTimeout(getLong(environment.get(JAXRS_CLIENT_READ_TIMEOUT)), MICROSECONDS); } if (environment.contains(JAXRS_CLIENT_SCHEDULED_EXECUTOR_SERVICE)) { @@ -230,11 +233,19 @@ private ClientBuilder getClientBuilder() throws ClassNotFoundException, Instanti clientBuilder.withConfig(getInstance(environment.get(JAXRS_CLIENT_CONFIG), Configuration.class)); } + String providerPrincipal = (String)environment.get(PROVIDER_PRINCIPAL); + String providerCredentials = (String)environment.get(PROVIDER_CREDENTIALS); + if (providerPrincipal != null && providerCredentials != null) { + String authType = (String)environment.get(PROVIDER_AUTH_TYPE); + if (authType == null || BASIC_AUTH.equals(authType)) { + clientBuilder.register(new BasicAuthFilter(providerPrincipal, providerCredentials)); + } + } return clientBuilder; } private static NamingException newNamingException(String name, Exception cause) { - NamingException namingException = new NamingException("Could not lookup :" + name); + NamingException namingException = new NamingException("Could not lookup: " + name); namingException.initCause(cause); return namingException; diff --git a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContextFactory.java b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContextFactory.java index 64f420eb809..ed7d3490e7b 100644 --- a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContextFactory.java +++ b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContextFactory.java @@ -42,6 +42,8 @@ import java.util.Hashtable; import javax.naming.Context; +import static javax.naming.Context.SECURITY_CREDENTIALS; +import static javax.naming.Context.SECURITY_PRINCIPAL; import javax.naming.NamingException; import javax.naming.spi.InitialContextFactory; @@ -70,6 +72,10 @@ public class RemoteEJBContextFactory implements InitialContextFactory { public static final String FACTORY_CLASS = RemoteEJBContextFactory.class.getName(); public static final String CLIENT_ADAPTER = "fish.payara.clientAdapter"; + public static final String PROVIDER_AUTH_TYPE = "fish.payara.provider.auth.type"; + public static final String PROVIDER_PRINCIPAL = "fish.payara.provider.principal"; + public static final String PROVIDER_CREDENTIALS = "fish.payara.provider.credentials"; + public static final String JAXRS_CLIENT_CONFIG = "fish.payara.withConfig"; public static final String JAXRS_CLIENT_TRUST_STORE = "fish.payara.trustStore"; public static final String JAXRS_CLIENT_SSL_CONTEXT = "fish.payara.sslContext"; diff --git a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/protocol/rs/BasicAuthFilter.java b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/protocol/rs/BasicAuthFilter.java new file mode 100644 index 00000000000..6ebdd5eb7ee --- /dev/null +++ b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/protocol/rs/BasicAuthFilter.java @@ -0,0 +1,70 @@ +/* + * 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 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.ejb.http.protocol.rs; + +import fish.payara.ejb.http.client.Lookup; +import java.io.IOException; +import javax.ws.rs.client.ClientRequestContext; +import javax.ws.rs.client.ClientRequestFilter; +import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; +import static javax.ws.rs.core.SecurityContext.BASIC_AUTH; + +/** + * + * @author Gaurav Gupta + */ +public class BasicAuthFilter implements ClientRequestFilter { + + private final String principal; + private final String credentials; + + public BasicAuthFilter(String principal, String credentials) { + this.principal = principal; + this.credentials = credentials; + } + + @Override + public void filter(ClientRequestContext requestContext) throws IOException { + String token = this.principal + ':' + this.credentials; + String basicAuthentication = BASIC_AUTH + ' ' + Lookup.base64Encode(token); + requestContext.getHeaders().add(AUTHORIZATION, basicAuthentication); + } + +} diff --git a/appserver/ejb/ejb-http-remoting/endpoint/src/main/java/fish/payara/ejb/http/endpoint/EjbOverHttpResource.java b/appserver/ejb/ejb-http-remoting/endpoint/src/main/java/fish/payara/ejb/http/endpoint/EjbOverHttpResource.java index c9f3634a590..d63d4080faf 100644 --- a/appserver/ejb/ejb-http-remoting/endpoint/src/main/java/fish/payara/ejb/http/endpoint/EjbOverHttpResource.java +++ b/appserver/ejb/ejb-http-remoting/endpoint/src/main/java/fish/payara/ejb/http/endpoint/EjbOverHttpResource.java @@ -41,7 +41,6 @@ import static java.util.Arrays.asList; -import java.io.OutputStream; import java.io.Reader; import java.io.StringReader; import java.io.StringWriter; @@ -50,11 +49,8 @@ import java.net.URI; import java.util.Arrays; import java.util.Base64; -import java.util.Optional; import java.util.function.BiFunction; -import javax.json.JsonObject; -import javax.json.JsonValue; import javax.json.bind.JsonbBuilder; import javax.naming.InitialContext; import javax.naming.NamingException; From dc11fa461ad15769123bbb598962bd2e6db6896e Mon Sep 17 00:00:00 2001 From: Gaurav Gupta Date: Mon, 23 Sep 2019 13:48:39 +0530 Subject: [PATCH 02/15] PAYARA-3658 TransportGuarantee changed to CONFIDENTIAL --- .../payara/ejb/http/admin/EjbInvokerContainerInitializer.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerContainerInitializer.java b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerContainerInitializer.java index 0691a26849e..a04cedda8ee 100644 --- a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerContainerInitializer.java +++ b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerContainerInitializer.java @@ -46,7 +46,7 @@ import javax.servlet.ServletException; import javax.servlet.ServletRegistration; import javax.servlet.ServletSecurityElement; -import static javax.servlet.annotation.ServletSecurity.TransportGuarantee.NONE; +import static javax.servlet.annotation.ServletSecurity.TransportGuarantee.CONFIDENTIAL; import org.glassfish.internal.api.Globals; import java.util.logging.Logger; @@ -75,7 +75,7 @@ public void onStartup(Set> set, ServletContext ctx) throws ServletExcep String[] roles = configuration.getRoles().split(","); ServletRegistration.Dynamic reg = (ServletRegistration.Dynamic) ctx.getServletRegistration("fish.payara.ejb.http.endpoint.EjbOverHttpApplication"); if (reg != null) { - reg.setServletSecurity(new ServletSecurityElement(new HttpConstraintElement(NONE, roles))); + reg.setServletSecurity(new ServletSecurityElement(new HttpConstraintElement(CONFIDENTIAL, roles))); } else { LOGGER.warning("ejb-invoker endpoint not initialized"); } From aa2204b12ed1367b249e8b40d89f08ce373cca30 Mon Sep 17 00:00:00 2001 From: Gaurav Gupta Date: Mon, 23 Sep 2019 13:55:25 +0530 Subject: [PATCH 03/15] PAYARA-3658 ejb-invoker endpoint JASPIC ServerAuthModule configuration support --- appserver/ejb/ejb-http-remoting/admin/pom.xml | 5 + .../http/admin/EjbInvokerConfiguration.java | 20 +++- .../ejb/http/admin/EjbInvokerService.java | 34 ++++++- .../GetEjbInvokerConfigurationCommand.java | 6 +- .../SetEjbInvokerConfigurationCommand.java | 98 +++++++++++++++++-- .../javax.enterprise.inject.spi.Extension | 1 + .../javax.servlet.ServletContainerInitializer | 1 - .../ejb/ejb-http-remoting/endpoint/pom.xml | 11 +++ .../fish/payara/ejb/invoke/EjbInvoker.java | 25 +++++ .../EjbInvokerContainerInitializer.java | 34 ++++--- .../javax.servlet.ServletContainerInitializer | 1 + .../src/main/webapp/WEB-INF/beans.xml | 6 ++ .../src/main/webapp/WEB-INF/payara-web.xml | 5 + .../endpoint/src/main/webapp/WEB-INF/web.xml | 26 +++++ .../endpoint/src/main/webapp/error.xhtml | 58 +++++++++++ .../endpoint/src/main/webapp/login.xhtml | 57 +++++++++++ 16 files changed, 357 insertions(+), 31 deletions(-) create mode 100644 appserver/ejb/ejb-http-remoting/admin/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension delete mode 100644 appserver/ejb/ejb-http-remoting/admin/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer create mode 100644 appserver/ejb/ejb-http-remoting/endpoint/src/main/java/fish/payara/ejb/invoke/EjbInvoker.java rename appserver/ejb/ejb-http-remoting/{admin/src/main/java/fish/payara/ejb/http/admin => endpoint/src/main/java/fish/payara/ejb/invoke}/EjbInvokerContainerInitializer.java (68%) create mode 100644 appserver/ejb/ejb-http-remoting/endpoint/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer create mode 100644 appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/WEB-INF/beans.xml create mode 100644 appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/WEB-INF/payara-web.xml create mode 100644 appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/WEB-INF/web.xml create mode 100644 appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/error.xhtml create mode 100644 appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/login.xhtml diff --git a/appserver/ejb/ejb-http-remoting/admin/pom.xml b/appserver/ejb/ejb-http-remoting/admin/pom.xml index 95dde51ebeb..d68df0b3b9f 100644 --- a/appserver/ejb/ejb-http-remoting/admin/pom.xml +++ b/appserver/ejb/ejb-http-remoting/admin/pom.xml @@ -68,6 +68,11 @@ internal-api ${project.version} + + fish.payara.server.internal.web + web-glue + ${project.version} + javax javaee-api diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerConfiguration.java b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerConfiguration.java index b51d91653a3..85ebe65cc8f 100644 --- a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerConfiguration.java +++ b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerConfiguration.java @@ -43,6 +43,7 @@ import static fish.payara.ejb.http.admin.Constants.DEFAULT_ENDPOINT; import static fish.payara.ejb.http.admin.Constants.DEFAULT_GROUP_NAME; import java.beans.PropertyVetoException; +import javax.security.enterprise.identitystore.IdentityStore; import static javax.servlet.http.HttpServletRequest.BASIC_AUTH; import org.glassfish.api.admin.config.ConfigExtension; import org.jvnet.hk2.config.Attribute; @@ -105,11 +106,28 @@ public interface EjbInvokerConfiguration extends ConfigBeanProxy, ConfigExtensio * @return a String value defines the name of the authentication mechanism * used to protect the ejb-invoker endpoint. */ - @Attribute(defaultValue = BASIC_AUTH, dataType = String.class) + @Attribute(dataType = String.class) String getAuthType(); void setAuthType(String value) throws PropertyVetoException; + /** + * @return a String value defines the id of message-security-provider. + */ + @Attribute(dataType = String.class) + String getAuthModule(); + + void setAuthModule(String value) throws PropertyVetoException; + + /** + * @return a String value defines the name of class implementing the + * {@code javax.security.auth.message.module.ServerAuthModule}. + */ + @Attribute(dataType = String.class) + String getAuthModuleClass(); + + void setAuthModuleClass(String value) throws PropertyVetoException; + /** * @return a String value defines the roles. */ diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerService.java b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerService.java index 5855f633fdd..e0994d5fd14 100644 --- a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerService.java +++ b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerService.java @@ -42,11 +42,13 @@ import com.sun.enterprise.config.serverbeans.SecurityService; import com.sun.enterprise.deployment.Application; import com.sun.enterprise.deployment.WebBundleDescriptor; +import static com.sun.enterprise.deployment.runtime.web.SunWebApp.HTTPSERVLET_SECURITY_PROVIDER; import com.sun.enterprise.deployment.web.LoginConfiguration; import com.sun.enterprise.util.StringUtils; import static fish.payara.ejb.http.admin.Constants.EJB_INVOKER_APP; import javax.annotation.PostConstruct; import javax.inject.Inject; +import static javax.servlet.http.HttpServletRequest.FORM_AUTH; import org.glassfish.api.StartupRunLevel; import org.glassfish.api.deployment.DeploymentContext; import org.glassfish.api.event.EventListener; @@ -54,6 +56,7 @@ import org.glassfish.hk2.runlevel.RunLevel; import org.glassfish.internal.api.Globals; import org.glassfish.internal.deployment.Deployment; +import org.glassfish.web.deployment.runtime.SunWebAppImpl; import org.jvnet.hk2.annotations.Service; /** * @@ -81,17 +84,38 @@ public void init() { } @Override - public void event(EventListener.Event event) {//event.type().type() + public void event(EventListener.Event event) { if (event.is(Deployment.APPLICATION_PREPARED)) { DeploymentContext context = (DeploymentContext) event.hook(); Application app = context.getModuleMetaData(Application.class); - if (EJB_INVOKER_APP.equals(app.getAppName())) { + if (EJB_INVOKER_APP.equals(app.getAppName()) + && Boolean.parseBoolean(config.getSecurityEnabled())) { for (WebBundleDescriptor descriptor : app.getBundleDescriptors(WebBundleDescriptor.class)) { + SunWebAppImpl webApp = (SunWebAppImpl) descriptor.getSunDescriptor(); + String moduleName; + if (StringUtils.ok(config.getAuthModuleClass()) + && config.getAuthModuleClass().indexOf('.') != -1) { + moduleName = config.getAuthModuleClass().substring(config.getAuthModuleClass().lastIndexOf('.') + 1); + webApp.setAttributeValue(HTTPSERVLET_SECURITY_PROVIDER, moduleName); + } else if (StringUtils.ok(config.getAuthModule())) { + moduleName = config.getAuthModule(); + webApp.setAttributeValue(HTTPSERVLET_SECURITY_PROVIDER, moduleName); + } LoginConfiguration loginConf = descriptor.getLoginConfiguration(); - loginConf.setAuthenticationMethod(config.getAuthType()); - loginConf.setRealmName(StringUtils.ok(config.getRealmName()) ? config.getRealmName() : securityService.getDefaultRealm()); + String authType = config.getAuthType(); + String realmName = config.getRealmName(); + if (StringUtils.ok(authType)) { + loginConf.setAuthenticationMethod(authType); + } + if (StringUtils.ok(realmName)) { + loginConf.setRealmName(realmName); + } + if (FORM_AUTH.equals(config.getAuthType())) { + loginConf.setFormErrorPage("/error.xhtml"); + loginConf.setFormLoginPage("/login.xhtml"); + } } } } } -} \ No newline at end of file +} diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/GetEjbInvokerConfigurationCommand.java b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/GetEjbInvokerConfigurationCommand.java index 973f8ac5cca..ecf4f02f27a 100644 --- a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/GetEjbInvokerConfigurationCommand.java +++ b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/GetEjbInvokerConfigurationCommand.java @@ -81,7 +81,7 @@ }) public class GetEjbInvokerConfigurationCommand implements AdminCommand { - private final String[] OUTPUT_HEADERS = {"Enabled", "EndPoint", "VirtualServers", "Security Enabled", "Realm Name", "Auth Type", "Roles"}; + private final String[] OUTPUT_HEADERS = {"Enabled", "EndPoint", "VirtualServers", "Security Enabled", "Realm Name", "Auth Type", "Auth Module", "Auth Module Class", "Roles"}; @Inject private Target targetUtil; @@ -110,6 +110,8 @@ public void execute(AdminCommandContext adminCommandContext) { configuration.getSecurityEnabled(), configuration.getRealmName(), configuration.getAuthType(), + configuration.getAuthModule(), + configuration.getAuthModuleClass(), configuration.getRoles() }; columnFormatter.addRow(outputValues); @@ -123,6 +125,8 @@ public void execute(AdminCommandContext adminCommandContext) { extraPropertiesMap.put("securityEnabled", configuration.getSecurityEnabled()); extraPropertiesMap.put("realmName", configuration.getRealmName()); extraPropertiesMap.put("authType", configuration.getAuthType()); + extraPropertiesMap.put("authModule", configuration.getAuthModule()); + extraPropertiesMap.put("authModuleClass", configuration.getAuthModuleClass()); extraPropertiesMap.put("roles", configuration.getRoles()); Properties extraProperties = new Properties(); diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/SetEjbInvokerConfigurationCommand.java b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/SetEjbInvokerConfigurationCommand.java index e1ea88b3d6c..10acd089566 100644 --- a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/SetEjbInvokerConfigurationCommand.java +++ b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/SetEjbInvokerConfigurationCommand.java @@ -51,6 +51,7 @@ import java.util.logging.Logger; import javax.inject.Inject; import javax.security.auth.Subject; +import static javax.servlet.http.HttpServletRequest.FORM_AUTH; import org.glassfish.api.ActionReport; import org.glassfish.api.Param; import org.glassfish.api.admin.AdminCommand; @@ -120,6 +121,12 @@ public class SetEjbInvokerConfigurationCommand implements AdminCommand { @Param(optional = true, alias = "authtype") protected String authType; + @Param(optional = true, alias = "authmodule") + protected String authModule; + + @Param(optional = true, alias = "authmoduleclass") + protected String authModuleClass; + @Param(optional = true) protected String roles; @@ -168,6 +175,19 @@ public void execute(AdminCommandContext context) { if (authType != null) { configProxy.setAuthType(authType); } + if (authModule != null) { + configProxy.setAuthModule(authModule); + } + if (authModuleClass != null) { + if (StringUtils.ok(authModuleClass) + && authModuleClass.indexOf('.') == -1) { + actionReport.failure( + LOGGER, + "authModuleClass parameter value must be fully qualified class name." + ); + } + configProxy.setAuthModuleClass(authModuleClass); + } if (roles != null) { configProxy.setRoles(roles); } @@ -181,16 +201,35 @@ public void execute(AdminCommandContext context) { if (Boolean.parseBoolean(config.getEnabled()) && Boolean.parseBoolean(config.getSecurityEnabled())) { - // Create the default user if it doesn't exist - ActionReport checkUserReport = actionReport.addSubActionsReport(); - ActionReport createUserReport = actionReport.addSubActionsReport(); - if (!defaultUserExists(config, checkUserReport, subject) - && !checkUserReport.hasFailures()) { - createDefaultUser(config, createUserReport, subject); + + // If the required message security provider is not present, create it + if (StringUtils.ok(config.getAuthModuleClass())) { + String moduleClass = config.getAuthModuleClass(); + String moduleId = moduleClass.substring(moduleClass.lastIndexOf('.') + 1); + ActionReport checkSecurityProviderReport = actionReport.addSubActionsReport(); + ActionReport createSecurityProviderReport = actionReport.addSubActionsReport(); + if (!messageSecurityProviderExists(moduleId, checkSecurityProviderReport, + context.getSubject())) { + createRequiredMessageSecurityProvider(moduleId, moduleClass, createSecurityProviderReport, subject); + } + if (checkSecurityProviderReport.hasFailures() || createSecurityProviderReport.hasFailures()) { + actionReport.setActionExitCode(ActionReport.ExitCode.FAILURE); + return; + } } - if (checkUserReport.hasFailures() || createUserReport.hasFailures()) { - actionReport.setActionExitCode(ActionReport.ExitCode.FAILURE); - return; + + // Create the default user if it doesn't exist + if (!StringUtils.ok(config.getRealmName()) || config.getRealmName().equals("file")) { + ActionReport checkUserReport = actionReport.addSubActionsReport(); + ActionReport createUserReport = actionReport.addSubActionsReport(); + if (!defaultUserExists(config, checkUserReport, subject) + && !checkUserReport.hasFailures()) { + createDefaultUser(config, createUserReport, subject); + } + if (checkUserReport.hasFailures() || createUserReport.hasFailures()) { + actionReport.setActionExitCode(ActionReport.ExitCode.FAILURE); + return; + } } } @@ -208,7 +247,6 @@ public void execute(AdminCommandContext context) { } } - public void disableEjbInvoker(ActionReport report) { Path endPointsPath = serverEnvironment.getInstanceRoot().toPath().resolve(ENDPOINTS_DIR); Path ejbInvokerPath = endPointsPath.resolve(EJB_INVOKER_APP); @@ -257,6 +295,46 @@ public void enableEjbInvoker(ActionReport report) { } } + private boolean messageSecurityProviderExists(String authModule, ActionReport subActionReport, Subject subject) { + boolean exists = false; + + CommandRunner.CommandInvocation invocation + = commandRunner.getCommandInvocation( + "list-message-security-providers", + subActionReport, + subject, + false + ); + + ParameterMap parameters = new ParameterMap(); + parameters.add("layer", "HttpServlet"); + + invocation.parameters(parameters).execute(); + + for (ActionReport.MessagePart message : subActionReport.getTopMessagePart().getChildren()) { + if (message.getMessage().equals(authModule)) { + exists = true; + break; + } + } + + return exists; + } + + private void createRequiredMessageSecurityProvider(String authModule, String authModuleClass, ActionReport subActionReport, Subject subject) { + CommandRunner.CommandInvocation invocation = commandRunner.getCommandInvocation("create-message-security-provider", + subActionReport, subject, false); + ParameterMap parameters = new ParameterMap(); + parameters.add("classname", authModuleClass); + parameters.add("isdefaultprovider", "false"); + parameters.add("layer", "HttpServlet"); + parameters.add("providertype", "server"); + parameters.add("target", target); + parameters.add("requestauthsource", "sender"); + parameters.add("DEFAULT", authModule); + invocation.parameters(parameters).execute(); + } + protected boolean defaultUserExists(EjbInvokerConfiguration config, ActionReport subActionReport, Subject subject) { CommandRunner.CommandInvocation invocation = commandRunner.getCommandInvocation( diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/appserver/ejb/ejb-http-remoting/admin/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension new file mode 100644 index 00000000000..e705b463a08 --- /dev/null +++ b/appserver/ejb/ejb-http-remoting/admin/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension @@ -0,0 +1 @@ +fish.payara.ejb.http.admin.EjbInvokerExtension \ No newline at end of file diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer b/appserver/ejb/ejb-http-remoting/admin/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer deleted file mode 100644 index d1ea39bd7ce..00000000000 --- a/appserver/ejb/ejb-http-remoting/admin/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer +++ /dev/null @@ -1 +0,0 @@ -fish.payara.ejb.http.admin.EjbInvokerContainerInitializer diff --git a/appserver/ejb/ejb-http-remoting/endpoint/pom.xml b/appserver/ejb/ejb-http-remoting/endpoint/pom.xml index 6a1d7d04009..894ee67a7fe 100644 --- a/appserver/ejb/ejb-http-remoting/endpoint/pom.xml +++ b/appserver/ejb/ejb-http-remoting/endpoint/pom.xml @@ -117,6 +117,17 @@ jakarta.json test + + ${project.groupId} + ejb-http-admin + ${project.version} + provided + + + org.glassfish.jersey.containers + jersey-container-servlet + provided + diff --git a/appserver/ejb/ejb-http-remoting/endpoint/src/main/java/fish/payara/ejb/invoke/EjbInvoker.java b/appserver/ejb/ejb-http-remoting/endpoint/src/main/java/fish/payara/ejb/invoke/EjbInvoker.java new file mode 100644 index 00000000000..2f545cb55a4 --- /dev/null +++ b/appserver/ejb/ejb-http-remoting/endpoint/src/main/java/fish/payara/ejb/invoke/EjbInvoker.java @@ -0,0 +1,25 @@ +/* + * To change this license header, choose License Headers in Project Properties. + * To change this template file, choose Tools | Templates + * and open the template in the editor. + */ +package fish.payara.ejb.invoke; + +import static java.lang.annotation.ElementType.TYPE; +import static java.lang.annotation.ElementType.FIELD; +import static java.lang.annotation.ElementType.PARAMETER; +import static java.lang.annotation.ElementType.METHOD; +import static java.lang.annotation.RetentionPolicy.RUNTIME; +import java.lang.annotation.Retention; +import java.lang.annotation.Target; +import javax.inject.Qualifier; + +/** + * + * @author jGauravGupta + */ +@Qualifier +@Retention(RUNTIME) +@Target({METHOD, FIELD, PARAMETER, TYPE}) +public @interface EjbInvoker { +} diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerContainerInitializer.java b/appserver/ejb/ejb-http-remoting/endpoint/src/main/java/fish/payara/ejb/invoke/EjbInvokerContainerInitializer.java similarity index 68% rename from appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerContainerInitializer.java rename to appserver/ejb/ejb-http-remoting/endpoint/src/main/java/fish/payara/ejb/invoke/EjbInvokerContainerInitializer.java index a04cedda8ee..5a07823eebc 100644 --- a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerContainerInitializer.java +++ b/appserver/ejb/ejb-http-remoting/endpoint/src/main/java/fish/payara/ejb/invoke/EjbInvokerContainerInitializer.java @@ -37,8 +37,12 @@ * only if the new code is made subject to such option by the copyright * holder. */ -package fish.payara.ejb.http.admin; +package fish.payara.ejb.invoke; +import fish.payara.ejb.http.admin.EjbInvokerConfiguration; +import fish.payara.ejb.http.endpoint.EjbOverHttpApplication; +import static java.util.Arrays.asList; +import java.util.HashSet; import java.util.Set; import javax.servlet.HttpConstraintElement; import javax.servlet.ServletContainerInitializer; @@ -48,7 +52,8 @@ import javax.servlet.ServletSecurityElement; import static javax.servlet.annotation.ServletSecurity.TransportGuarantee.CONFIDENTIAL; import org.glassfish.internal.api.Globals; -import java.util.logging.Logger; +import static javax.servlet.http.HttpServletRequest.FORM_AUTH; +import org.glassfish.jersey.servlet.init.JerseyServletContainerInitializer; /** * @@ -56,28 +61,31 @@ */ public class EjbInvokerContainerInitializer implements ServletContainerInitializer { - private static final Logger LOGGER = Logger.getLogger(EjbInvokerContainerInitializer.class.getName()); - @Override public void onStartup(Set> set, ServletContext ctx) throws ServletException { - EjbInvokerConfiguration configuration = Globals.getDefaultBaseServiceLocator() + EjbInvokerConfiguration config = Globals.getDefaultBaseServiceLocator() .getService(EjbInvokerConfiguration.class); String endpoint = ctx.getContextPath(); if(endpoint.startsWith("/")){ endpoint = endpoint.substring(1); } - if (!configuration.getEndpoint().equals(endpoint)) { + if (!config.getEndpoint().equals(endpoint)) { return; } - if (Boolean.parseBoolean(configuration.getSecurityEnabled())) { - String[] roles = configuration.getRoles().split(","); - ServletRegistration.Dynamic reg = (ServletRegistration.Dynamic) ctx.getServletRegistration("fish.payara.ejb.http.endpoint.EjbOverHttpApplication"); - if (reg != null) { - reg.setServletSecurity(new ServletSecurityElement(new HttpConstraintElement(CONFIDENTIAL, roles))); - } else { - LOGGER.warning("ejb-invoker endpoint not initialized"); + if (Boolean.parseBoolean(config.getSecurityEnabled())) { + String[] roles = config.getRoles().split(","); + ServletRegistration.Dynamic reg = (ServletRegistration.Dynamic) ctx.getServletRegistration(EjbOverHttpApplication.class.getName()); + if (reg == null) { + new JerseyServletContainerInitializer().onStartup(new HashSet<>(asList(EjbOverHttpApplication.class)), ctx); + reg = (ServletRegistration.Dynamic) ctx.getServletRegistration(EjbOverHttpApplication.class.getName()); + } + reg.setServletSecurity(new ServletSecurityElement(new HttpConstraintElement(CONFIDENTIAL, roles))); + if (FORM_AUTH.equals(config.getAuthType())) { + ServletRegistration defaultRegistration = ctx.getServletRegistration("default"); + defaultRegistration.addMapping("/login.xhtml"); + defaultRegistration.addMapping("/error.xhtml"); } ctx.declareRoles(roles); } diff --git a/appserver/ejb/ejb-http-remoting/endpoint/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer b/appserver/ejb/ejb-http-remoting/endpoint/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer new file mode 100644 index 00000000000..91241097d40 --- /dev/null +++ b/appserver/ejb/ejb-http-remoting/endpoint/src/main/resources/META-INF/services/javax.servlet.ServletContainerInitializer @@ -0,0 +1 @@ +fish.payara.ejb.invoke.EjbInvokerContainerInitializer diff --git a/appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/WEB-INF/beans.xml b/appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 00000000000..ba9b101547f --- /dev/null +++ b/appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/WEB-INF/beans.xml @@ -0,0 +1,6 @@ + + + diff --git a/appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/WEB-INF/payara-web.xml b/appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/WEB-INF/payara-web.xml new file mode 100644 index 00000000000..5ce3c6502d6 --- /dev/null +++ b/appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/WEB-INF/payara-web.xml @@ -0,0 +1,5 @@ + + + + + diff --git a/appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/WEB-INF/web.xml b/appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/WEB-INF/web.xml new file mode 100644 index 00000000000..a6a0cf57c0b --- /dev/null +++ b/appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/WEB-INF/web.xml @@ -0,0 +1,26 @@ + + + + + + login + /login.xhtml + + + login + /login + + + + error + /error.xhtml + + + error + /login-error + + + diff --git a/appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/error.xhtml b/appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/error.xhtml new file mode 100644 index 00000000000..6caa8214973 --- /dev/null +++ b/appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/error.xhtml @@ -0,0 +1,58 @@ + + + + + + Login Error + + +

Invalid user name or password.

+ +

Please enter a user name or password that is authorized to access this + application. For this application, this means a user that has been + created in the file realm and has been assigned to the + group of TutorialUser.

+ Return to login page + +
+ + diff --git a/appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/login.xhtml b/appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/login.xhtml new file mode 100644 index 00000000000..68c9a216b9b --- /dev/null +++ b/appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/login.xhtml @@ -0,0 +1,57 @@ + + + + + + Ejb Invoker Login + + +
+

Username: +

+

Password: +

+

+
+
+ + From 60e50bc8aca379b7390d4b01bdcae45c799a7601 Mon Sep 17 00:00:00 2001 From: Gaurav Gupta Date: Wed, 2 Oct 2019 17:53:28 +0530 Subject: [PATCH 04/15] PAYARA-3658 Dynamically secure deprecated ejb-invoker v0 endpoint /ejb/* via roles check --- .../payara/ejb/invoke/InvokeEJBServlet.java | 22 +++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/appserver/ejb/ejb-http-remoting/endpoint/src/main/java/fish/payara/ejb/invoke/InvokeEJBServlet.java b/appserver/ejb/ejb-http-remoting/endpoint/src/main/java/fish/payara/ejb/invoke/InvokeEJBServlet.java index 1e6c5d37a73..cd9fb3dff45 100644 --- a/appserver/ejb/ejb-http-remoting/endpoint/src/main/java/fish/payara/ejb/invoke/InvokeEJBServlet.java +++ b/appserver/ejb/ejb-http-remoting/endpoint/src/main/java/fish/payara/ejb/invoke/InvokeEJBServlet.java @@ -40,6 +40,7 @@ package fish.payara.ejb.invoke; import com.sun.enterprise.security.ee.auth.login.ProgrammaticLogin; +import fish.payara.ejb.http.admin.EjbInvokerConfiguration; import fish.payara.ejb.http.endpoint.EjbOverHttpResource; @@ -70,6 +71,7 @@ import java.util.Base64; import java.util.logging.Level; import java.util.logging.Logger; +import javax.inject.Inject; import static javax.naming.Context.SECURITY_CREDENTIALS; import static javax.naming.Context.SECURITY_PRINCIPAL; @@ -82,10 +84,22 @@ @Deprecated @WebServlet("/ejb/*") public class InvokeEJBServlet extends HttpServlet { + private static final long serialVersionUID = 1L; private static final Logger logger = Logger.getLogger(InvokeEJBServlet.class.getName()); + private boolean securityEnabled; + + private String[] roles; + + public void init() throws ServletException { + EjbInvokerConfiguration config = Globals.getDefaultBaseServiceLocator() + .getService(EjbInvokerConfiguration.class); + roles = config.getRoles().split(","); + securityEnabled = Boolean.parseBoolean(config.getSecurityEnabled()); + } + @Override protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.getWriter().append("Served at: ").append(request.getContextPath()); @@ -95,6 +109,14 @@ protected void doGet(HttpServletRequest request, HttpServletResponse response) t protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { JsonObject requestPayload = readJsonObject(request.getReader()); + if(securityEnabled) { + for(String role : roles) { + if(!request.isUserInRole(role)) { + response.setStatus(HttpServletResponse.SC_FORBIDDEN); + } + } + } + String beanName = requestPayload.getString("lookup"); if (request.getRequestURI().endsWith("lookup")) { try { From b829044919d139590282ea14a5fd720e5b9708bc Mon Sep 17 00:00:00 2001 From: Gaurav Gupta Date: Wed, 2 Oct 2019 17:56:34 +0530 Subject: [PATCH 05/15] PAYARA-3658 Fix ejb-invoker javax.ws.rs.client.ClientBuilder environment conditions --- .../ejb/http/client/RemoteEJBContext.java | 19 +++++++++++-------- .../http/client/RemoteEJBContextFactory.java | 1 + 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContext.java b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContext.java index 1688b6c1799..9bfe18e51cb 100644 --- a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContext.java +++ b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContext.java @@ -201,35 +201,38 @@ private ClientBuilder getClientBuilder() throws ClassNotFoundException, Instanti clientBuilder.connectTimeout(getLong(environment.get(JAXRS_CLIENT_CONNECT_TIMEOUT)), MICROSECONDS); } - if (environment.contains(JAXRS_CLIENT_EXECUTOR_SERVICE)) { + if (environment.containsKey(JAXRS_CLIENT_EXECUTOR_SERVICE)) { clientBuilder.executorService(getInstance(environment.get(JAXRS_CLIENT_EXECUTOR_SERVICE), ExecutorService.class)); } - if (environment.contains(JAXRS_CLIENT_HOSTNAME_VERIFIER)) { + if (environment.containsKey(JAXRS_CLIENT_HOSTNAME_VERIFIER)) { clientBuilder.hostnameVerifier(getInstance(environment.get(JAXRS_CLIENT_HOSTNAME_VERIFIER), HostnameVerifier.class)); } - if (environment.contains(JAXRS_CLIENT_KEY_STORE)) { - clientBuilder.keyStore(getInstance(environment.get(JAXRS_CLIENT_KEY_STORE), KeyStore.class), getPassword(environment.get("keyStorePassword"))); + if (environment.containsKey(JAXRS_CLIENT_KEY_STORE)) { + clientBuilder.keyStore( + getInstance(environment.get(JAXRS_CLIENT_KEY_STORE), KeyStore.class), + getPassword(environment.containsKey("keyStorePassword") ? environment.get("keyStorePassword") : environment.get(JAXRS_CLIENT_KEY_STORE_PASSOWRD)) + ); } if (environment.containsKey(JAXRS_CLIENT_READ_TIMEOUT)) { clientBuilder.readTimeout(getLong(environment.get(JAXRS_CLIENT_READ_TIMEOUT)), MICROSECONDS); } - if (environment.contains(JAXRS_CLIENT_SCHEDULED_EXECUTOR_SERVICE)) { + if (environment.containsKey(JAXRS_CLIENT_SCHEDULED_EXECUTOR_SERVICE)) { clientBuilder.scheduledExecutorService(getInstance(environment.get(JAXRS_CLIENT_SCHEDULED_EXECUTOR_SERVICE), ScheduledExecutorService.class)); } - if (environment.contains(JAXRS_CLIENT_SSL_CONTEXT)) { + if (environment.containsKey(JAXRS_CLIENT_SSL_CONTEXT)) { clientBuilder.sslContext(getInstance(environment.get(JAXRS_CLIENT_SSL_CONTEXT), SSLContext.class)); } - if (environment.contains(JAXRS_CLIENT_TRUST_STORE)) { + if (environment.containsKey(JAXRS_CLIENT_TRUST_STORE)) { clientBuilder.trustStore(getInstance(environment.get(JAXRS_CLIENT_TRUST_STORE), KeyStore.class)); } - if (environment.contains(JAXRS_CLIENT_CONFIG)) { + if (environment.containsKey(JAXRS_CLIENT_CONFIG)) { clientBuilder.withConfig(getInstance(environment.get(JAXRS_CLIENT_CONFIG), Configuration.class)); } diff --git a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContextFactory.java b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContextFactory.java index ed7d3490e7b..2b89a183df7 100644 --- a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContextFactory.java +++ b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContextFactory.java @@ -82,6 +82,7 @@ public class RemoteEJBContextFactory implements InitialContextFactory { public static final String JAXRS_CLIENT_SCHEDULED_EXECUTOR_SERVICE = "fish.payara.scheduledExecutorService"; public static final String JAXRS_CLIENT_READ_TIMEOUT = "fish.payara.readTimeout"; public static final String JAXRS_CLIENT_KEY_STORE = "fish.payara.keyStore"; + public static final String JAXRS_CLIENT_KEY_STORE_PASSOWRD = "fish.payara.keyStorePassword"; public static final String JAXRS_CLIENT_HOSTNAME_VERIFIER = "fish.payara.hostnameVerifier"; public static final String JAXRS_CLIENT_EXECUTOR_SERVICE = "fish.payara.executorService"; public static final String JAXRS_CLIENT_CONNECT_TIMEOUT = "fish.payara.connectTimeout"; From 7940bbbd298c716b0e34064764e05968dc8a05e9 Mon Sep 17 00:00:00 2001 From: Gaurav Gupta Date: Thu, 3 Oct 2019 14:05:10 +0530 Subject: [PATCH 06/15] PAYARA-3658 ejb-invoker endpoint security testcase --- .../ejb/http/protocol/rs/BasicAuthFilter.java | 70 -------- .../ejb-invoker-secure-endpoint/pom.xml | 27 +++ .../samples/ejb/invoker/security/Bean.java | 56 ++++++ .../ejb/invoker/security/RemoteBean.java | 47 +++++ .../src/main/webapp/WEB-INF/beans.xml | 7 + .../AbstractRemoteBeanSecurityTest.java | 166 ++++++++++++++++++ .../security/RemoteBeanBasicAuthTest.java | 99 +++++++++++ .../security/RemoteBeanCustomRealmTest.java | 109 ++++++++++++ .../security/RemoteBeanCustomRoleTest.java | 99 +++++++++++ .../src/test/resources/addUsersPayara.txt | 1 + .../src/test/resources/password.txt | 1 + .../tests/payara-samples/samples/pom.xml | 3 +- .../fish/payara/samples/ServerOperations.java | 53 +++++- 13 files changed, 662 insertions(+), 76 deletions(-) delete mode 100644 appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/protocol/rs/BasicAuthFilter.java create mode 100644 appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/pom.xml create mode 100644 appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/main/java/fish/payara/samples/ejb/invoker/security/Bean.java create mode 100644 appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/main/java/fish/payara/samples/ejb/invoker/security/RemoteBean.java create mode 100644 appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/main/webapp/WEB-INF/beans.xml create mode 100644 appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/java/fish/payara/samples/ejb/invoker/security/AbstractRemoteBeanSecurityTest.java create mode 100644 appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/java/fish/payara/samples/ejb/invoker/security/RemoteBeanBasicAuthTest.java create mode 100644 appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/java/fish/payara/samples/ejb/invoker/security/RemoteBeanCustomRealmTest.java create mode 100644 appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/java/fish/payara/samples/ejb/invoker/security/RemoteBeanCustomRoleTest.java create mode 100644 appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/resources/addUsersPayara.txt create mode 100644 appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/resources/password.txt diff --git a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/protocol/rs/BasicAuthFilter.java b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/protocol/rs/BasicAuthFilter.java deleted file mode 100644 index 6ebdd5eb7ee..00000000000 --- a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/protocol/rs/BasicAuthFilter.java +++ /dev/null @@ -1,70 +0,0 @@ -/* - * 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 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.ejb.http.protocol.rs; - -import fish.payara.ejb.http.client.Lookup; -import java.io.IOException; -import javax.ws.rs.client.ClientRequestContext; -import javax.ws.rs.client.ClientRequestFilter; -import static javax.ws.rs.core.HttpHeaders.AUTHORIZATION; -import static javax.ws.rs.core.SecurityContext.BASIC_AUTH; - -/** - * - * @author Gaurav Gupta - */ -public class BasicAuthFilter implements ClientRequestFilter { - - private final String principal; - private final String credentials; - - public BasicAuthFilter(String principal, String credentials) { - this.principal = principal; - this.credentials = credentials; - } - - @Override - public void filter(ClientRequestContext requestContext) throws IOException { - String token = this.principal + ':' + this.credentials; - String basicAuthentication = BASIC_AUTH + ' ' + Lookup.base64Encode(token); - requestContext.getHeaders().add(AUTHORIZATION, basicAuthentication); - } - -} diff --git a/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/pom.xml b/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/pom.xml new file mode 100644 index 00000000000..212f922b5e2 --- /dev/null +++ b/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/pom.xml @@ -0,0 +1,27 @@ + + + 4.0.0 + + + fish.payara.samples + samples-parent + 5.194-SNAPSHOT + + + ejb-invoker-secure-endpoint + war + Payara Samples - Payara - ejb-invoker Secure Endpoint + + + + org.valid4j + http-matchers + test + + + fish.payara.extras + ejb-http-client + ${payara.version} + + + \ No newline at end of file diff --git a/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/main/java/fish/payara/samples/ejb/invoker/security/Bean.java b/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/main/java/fish/payara/samples/ejb/invoker/security/Bean.java new file mode 100644 index 00000000000..afe553ade58 --- /dev/null +++ b/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/main/java/fish/payara/samples/ejb/invoker/security/Bean.java @@ -0,0 +1,56 @@ +/* + * 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 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.samples.ejb.invoker.security; + +import java.io.Serializable; + +import javax.ejb.Stateless; + +@Stateless +public class Bean implements RemoteBean, Serializable { + + private static final long serialVersionUID = 1L; + + @Override + public String method() { + return "method"; + } + +} diff --git a/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/main/java/fish/payara/samples/ejb/invoker/security/RemoteBean.java b/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/main/java/fish/payara/samples/ejb/invoker/security/RemoteBean.java new file mode 100644 index 00000000000..2cb1c0aa56a --- /dev/null +++ b/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/main/java/fish/payara/samples/ejb/invoker/security/RemoteBean.java @@ -0,0 +1,47 @@ +/* + * 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 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.samples.ejb.invoker.security; + +import javax.ejb.Remote; + +@Remote +public interface RemoteBean { + String method(); +} diff --git a/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/main/webapp/WEB-INF/beans.xml b/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/main/webapp/WEB-INF/beans.xml new file mode 100644 index 00000000000..9cc04e3069d --- /dev/null +++ b/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/main/webapp/WEB-INF/beans.xml @@ -0,0 +1,7 @@ + + + \ No newline at end of file diff --git a/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/java/fish/payara/samples/ejb/invoker/security/AbstractRemoteBeanSecurityTest.java b/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/java/fish/payara/samples/ejb/invoker/security/AbstractRemoteBeanSecurityTest.java new file mode 100644 index 00000000000..2c0fa7801f7 --- /dev/null +++ b/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/java/fish/payara/samples/ejb/invoker/security/AbstractRemoteBeanSecurityTest.java @@ -0,0 +1,166 @@ +/* + * 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 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.samples.ejb.invoker.security; + +import fish.payara.ejb.http.client.RemoteEJBContextFactory; +import static fish.payara.ejb.http.client.RemoteEJBContextFactory.JAXRS_CLIENT_KEY_STORE; +import static fish.payara.ejb.http.client.RemoteEJBContextFactory.JAXRS_CLIENT_KEY_STORE_PASSOWRD; +import static fish.payara.ejb.http.client.RemoteEJBContextFactory.JAXRS_CLIENT_PROTOCOL_VERSION; +import static fish.payara.ejb.http.client.RemoteEJBContextFactory.JAXRS_CLIENT_SERIALIZATION; +import static fish.payara.ejb.http.client.RemoteEJBContextFactory.JAXRS_CLIENT_TRUST_STORE; +import static fish.payara.ejb.http.client.RemoteEJBContextFactory.PROVIDER_AUTH_TYPE; +import static fish.payara.ejb.http.client.RemoteEJBContextFactory.PROVIDER_CREDENTIALS; +import static fish.payara.ejb.http.client.RemoteEJBContextFactory.PROVIDER_PRINCIPAL; +import fish.payara.ejb.http.protocol.SerializationType; +import fish.payara.samples.ServerOperations; +import static fish.payara.samples.ServerOperations.getClientTrustStoreURL; +import static fish.payara.samples.ServerOperations.getKeyStore; +import java.io.File; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Hashtable; +import javax.naming.Context; +import static javax.naming.Context.INITIAL_CONTEXT_FACTORY; +import static javax.naming.Context.PROVIDER_URL; +import javax.naming.InitialContext; +import javax.naming.NamingException; +import static javax.ws.rs.core.SecurityContext.BASIC_AUTH; +import static javax.ws.rs.core.SecurityContext.CLIENT_CERT_AUTH; +import org.jboss.arquillian.container.test.api.Deployment; +import org.jboss.arquillian.container.test.api.RunAsClient; +import org.jboss.arquillian.test.api.ArquillianResource; +import org.jboss.shrinkwrap.api.Archive; +import org.jboss.shrinkwrap.api.ShrinkWrap; +import static org.jboss.shrinkwrap.api.asset.EmptyAsset.INSTANCE; +import org.jboss.shrinkwrap.api.spec.JavaArchive; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertNotNull; +import static org.junit.Assert.fail; +import org.junit.Test; + +/** + * + * @author jGauravGupta + */ +public abstract class AbstractRemoteBeanSecurityTest { + + private static final String EJB_INVOKER_PROVIDER_URL = "https://localhost:8181/ejb-invoker"; + + @ArquillianResource + private URL base; + + private static String clientKeyStorePath; + + @Deployment + public static Archive deployment() { + clientKeyStorePath = ServerOperations.createClientKeyStore(); + return ShrinkWrap.create(JavaArchive.class) + .addClasses(Bean.class, RemoteBean.class) + .addAsManifestResource(INSTANCE, "beans.xml"); + } + + private Context getContextWithCredentialsSet(String username, String password) { + Hashtable environment = new Hashtable<>(); + environment.put(INITIAL_CONTEXT_FACTORY, RemoteEJBContextFactory.class.getName()); + environment.put(PROVIDER_URL, EJB_INVOKER_PROVIDER_URL); + environment.put(PROVIDER_AUTH_TYPE, BASIC_AUTH); + environment.put(PROVIDER_PRINCIPAL, username); + environment.put(PROVIDER_CREDENTIALS, password); + environment.put(JAXRS_CLIENT_SERIALIZATION, SerializationType.JSON.toString()); + environment.put(JAXRS_CLIENT_PROTOCOL_VERSION, String.valueOf(1)); + createClientCertificateStore(environment); + try { + return new InitialContext(environment); + } catch (NamingException ex) { + throw new IllegalStateException(ex); + } + } + + private void createClientCertificateStore(Hashtable environment) { + try { + URL baseHttps = ServerOperations.toContainerHttps(base); + if (baseHttps == null) { + throw new IllegalStateException("No https URL could be created from " + base); + } + + String type = "jks"; + String password = "changeit"; + environment.put(JAXRS_CLIENT_TRUST_STORE, + getKeyStore(getClientTrustStoreURL(baseHttps, clientKeyStorePath), password, type)); + environment.put(JAXRS_CLIENT_KEY_STORE, + getKeyStore(new File(clientKeyStorePath).toURI().toURL(), password, type)); + environment.put(JAXRS_CLIENT_KEY_STORE_PASSOWRD, + password); + + } catch (MalformedURLException ex) { + throw new IllegalStateException(ex); + } + } + + @Test + @RunAsClient + public void callRemoteBeanWithCorrectCredentials() throws NamingException { + // Obtain the JNDI naming context + Context ejbRemoteContext = getContextWithCredentialsSet(getUserName(), getPassword()); + + RemoteBean beanRemote = (RemoteBean) ejbRemoteContext.lookup("java:global/test/Bean"); + assertNotNull(beanRemote.method()); + } + + @Test + @RunAsClient + public void callRemoteBeanWithIncorrectCredentials() throws NamingException { + // Obtain the JNDI naming context + Context ejbRemoteContext = getContextWithCredentialsSet(getUserName(), "InvalidPassword"); + + try { + RemoteBean beanRemote = (RemoteBean) ejbRemoteContext.lookup("java:global/test/Bean"); + assertNotNull(beanRemote.method()); + fail("RemoteBean#method must not be accessed for invalid credential"); + } catch (NamingException ex) { + assertEquals("Invoker is not available at <" + EJB_INVOKER_PROVIDER_URL + ">: Unauthorized", ex.getExplanation()); + } + } + + protected abstract String getUserName(); + + protected abstract String getPassword(); + +} diff --git a/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/java/fish/payara/samples/ejb/invoker/security/RemoteBeanBasicAuthTest.java b/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/java/fish/payara/samples/ejb/invoker/security/RemoteBeanBasicAuthTest.java new file mode 100644 index 00000000000..905271b101a --- /dev/null +++ b/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/java/fish/payara/samples/ejb/invoker/security/RemoteBeanBasicAuthTest.java @@ -0,0 +1,99 @@ +/* + * 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 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.samples.ejb.invoker.security; + +import fish.payara.samples.CliCommands; +import static fish.payara.samples.ServerOperations.addUsersToContainerIdentityStore; +import static java.util.Arrays.asList; +import static javax.ws.rs.core.SecurityContext.BASIC_AUTH; +import org.jboss.arquillian.junit.Arquillian; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; + +/** + * Calls an EJB bean from a remote server via ejb-invoker endpoint secured with + * BASIC Auth. + * + */ +@RunWith(Arquillian.class) +public class RemoteBeanBasicAuthTest extends AbstractRemoteBeanSecurityTest { + + private static final String USERNAME = "myuser"; + private static final String PASSWORD = "mypassword"; + private static final String ROLE = "invoker"; + + @BeforeClass + public static void enableSecurity() { + // undeploy the ejb-invoker app + CliCommands.payaraGlassFish(asList("set-ejb-invoker-configuration", + "--enabled", "false")); + // enable the security and deploy the ejb-invoker app + CliCommands.payaraGlassFish(asList("set-ejb-invoker-configuration", + "--enabled", "true", + "--securityenabled", "true", + "--authType", BASIC_AUTH)); + + // Add user with password and group to the container's native identity store + addUsersToContainerIdentityStore(USERNAME, ROLE, "file"); + } + + @AfterClass + public static void resetSecurity() { + // undeploy the ejb-invoker app + CliCommands.payaraGlassFish(asList("set-ejb-invoker-configuration", + "--enabled", "false")); + // disable the security and deploy the ejb-invoker app + CliCommands.payaraGlassFish(asList("set-ejb-invoker-configuration", + "--enabled", "true", + "--securityenabled", "false")); + } + + @Override + protected String getUserName() { + return USERNAME; + } + + @Override + protected String getPassword() { + return PASSWORD; + } + +} diff --git a/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/java/fish/payara/samples/ejb/invoker/security/RemoteBeanCustomRealmTest.java b/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/java/fish/payara/samples/ejb/invoker/security/RemoteBeanCustomRealmTest.java new file mode 100644 index 00000000000..4433bee9a28 --- /dev/null +++ b/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/java/fish/payara/samples/ejb/invoker/security/RemoteBeanCustomRealmTest.java @@ -0,0 +1,109 @@ +/* + * 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 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.samples.ejb.invoker.security; + +import fish.payara.samples.CliCommands; +import static fish.payara.samples.ServerOperations.addUsersToContainerIdentityStore; +import static java.util.Arrays.asList; +import org.jboss.arquillian.junit.Arquillian; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; + +/** + * Calls an EJB bean from a remote server via ejb-invoker endpoint secured with + * custom realm. + * + */ +@RunWith(Arquillian.class) +public class RemoteBeanCustomRealmTest extends AbstractRemoteBeanSecurityTest { + + private static final String USERNAME = "myuser_customrealm"; + private static final String PASSWORD = "mypassword"; + private static final String ROLE = "invoker"; + private static final String REALM = "file_customrealm"; + + @BeforeClass + public static void enableSecurity() { + // create the new auth realm + CliCommands.payaraGlassFish(asList("create-auth-realm", + "--classname", "com.sun.enterprise.security.auth.realm.file.FileRealm", + "--login-module", "com.sun.enterprise.security.auth.login.FileLoginModule", + "--property", "jaas-context=fileRealm:file=" + REALM, REALM)); + + // undeploy the ejb-invoker app + CliCommands.payaraGlassFish(asList("set-ejb-invoker-configuration", + "--enabled", "false")); + // enable the security and deploy the ejb-invoker app + CliCommands.payaraGlassFish(asList("set-ejb-invoker-configuration", + "--enabled", "true", + "--securityenabled", "true", + "--realmName", REALM)); + + // Add user with password and group to the container's native identity store + addUsersToContainerIdentityStore(USERNAME, ROLE, REALM); + } + + @AfterClass + public static void resetSecurity() { + // delete the auth realm + CliCommands.payaraGlassFish(asList("delete-auth-realm", REALM)); + + // undeploy the ejb-invoker app + CliCommands.payaraGlassFish(asList("set-ejb-invoker-configuration", + "--enabled", "false")); + // disable the security and deploy the ejb-invoker app + CliCommands.payaraGlassFish(asList("set-ejb-invoker-configuration", + "--enabled", "true", + "--securityenabled", "false", + "--realmName", "file")); + } + + @Override + protected String getUserName() { + return USERNAME; + } + + @Override + protected String getPassword() { + return PASSWORD; + } + +} diff --git a/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/java/fish/payara/samples/ejb/invoker/security/RemoteBeanCustomRoleTest.java b/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/java/fish/payara/samples/ejb/invoker/security/RemoteBeanCustomRoleTest.java new file mode 100644 index 00000000000..5f84cbc772c --- /dev/null +++ b/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/java/fish/payara/samples/ejb/invoker/security/RemoteBeanCustomRoleTest.java @@ -0,0 +1,99 @@ +/* + * 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 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.samples.ejb.invoker.security; + +import fish.payara.samples.CliCommands; +import static fish.payara.samples.ServerOperations.addUsersToContainerIdentityStore; +import static java.util.Arrays.asList; +import org.jboss.arquillian.junit.Arquillian; +import org.junit.AfterClass; +import org.junit.BeforeClass; +import org.junit.runner.RunWith; + +/** + * Calls an EJB bean from a remote server via secured ejb-invoker endpoint + * accessible to custom defined roles. + * + */ +@RunWith(Arquillian.class) +public class RemoteBeanCustomRoleTest extends AbstractRemoteBeanSecurityTest { + + private static final String USERNAME = "myuser_customrole"; + private static final String PASSWORD = "mypassword"; + private static final String ROLE = "invoker_customrole"; + + @BeforeClass + public static void enableSecurity() { + // undeploy the ejb-invoker app + CliCommands.payaraGlassFish(asList("set-ejb-invoker-configuration", + "--enabled", "false")); + // enable the security, change the role and deploy the ejb-invoker app + CliCommands.payaraGlassFish(asList("set-ejb-invoker-configuration", + "--enabled", "true", + "--securityenabled", "true", + "--roles", ROLE)); + + // Add user with password and group to the container's native identity store + addUsersToContainerIdentityStore(USERNAME, ROLE, "file"); + } + + @AfterClass + public static void resetSecurity() { + // undeploy the ejb-invoker app + CliCommands.payaraGlassFish(asList("set-ejb-invoker-configuration", + "--enabled", "false")); + // disable the security, reset the role and deploy the ejb-invoker app + CliCommands.payaraGlassFish(asList("set-ejb-invoker-configuration", + "--enabled", "true", + "--securityenabled", "false", + "--roles", "invoker")); + } + + @Override + protected String getUserName() { + return USERNAME; + } + + @Override + protected String getPassword() { + return PASSWORD; + } + +} diff --git a/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/resources/addUsersPayara.txt b/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/resources/addUsersPayara.txt new file mode 100644 index 00000000000..505ed9e71f1 --- /dev/null +++ b/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/resources/addUsersPayara.txt @@ -0,0 +1 @@ +create-file-user --groups invoker --passwordfile ${project.build.directory}/test-classes/password.txt myuser \ No newline at end of file diff --git a/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/resources/password.txt b/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/resources/password.txt new file mode 100644 index 00000000000..4648068b85a --- /dev/null +++ b/appserver/tests/payara-samples/samples/ejb-invoker-secure-endpoint/src/test/resources/password.txt @@ -0,0 +1 @@ +AS_ADMIN_USERPASSWORD=mypassword diff --git a/appserver/tests/payara-samples/samples/pom.xml b/appserver/tests/payara-samples/samples/pom.xml index 06f0feda965..d51a70bf5cd 100644 --- a/appserver/tests/payara-samples/samples/pom.xml +++ b/appserver/tests/payara-samples/samples/pom.xml @@ -146,7 +146,6 @@ fish.payara.arquillian payara-client-ee7 - 1.1 test @@ -167,7 +166,6 @@ fish.payara.arquillian payara-client-ee8 - 1.1 test @@ -355,6 +353,7 @@ ejb-http-remoting + ejb-invoker-secure-endpoint diff --git a/appserver/tests/payara-samples/test-utils/src/main/java/fish/payara/samples/ServerOperations.java b/appserver/tests/payara-samples/test-utils/src/main/java/fish/payara/samples/ServerOperations.java index 1eaaaa39388..036b5b5a809 100644 --- a/appserver/tests/payara-samples/test-utils/src/main/java/fish/payara/samples/ServerOperations.java +++ b/appserver/tests/payara-samples/test-utils/src/main/java/fish/payara/samples/ServerOperations.java @@ -74,7 +74,7 @@ public static void addUserToContainerIdentityStore(String username, String group if ("glassfish-remote".equals(javaEEServer) || "payara-remote".equals(javaEEServer)) { - System.out.println("Adding user for glassfish-remote"); + System.out.println("Adding user for " + javaEEServer); List cmd = new ArrayList<>(); @@ -105,7 +105,11 @@ public static void addUserToContainerIdentityStore(String username, String group * supported containers */ public static void addUsersToContainerIdentityStore() { + addUsersToContainerIdentityStore("u1", "g1", "file"); + } + public static void addUsersToContainerIdentityStore(String username, String group, String fileAuthRealmName) { + // TODO: abstract adding container managed users to utility class // TODO: consider PR for sending CLI commands to Arquillian @@ -113,17 +117,19 @@ public static void addUsersToContainerIdentityStore() { if ("glassfish-remote".equals(javaEEServer) || "payara-remote".equals(javaEEServer)) { - System.out.println("Adding user for glassfish-remote"); + System.out.println("Adding user for " + javaEEServer); List cmd = new ArrayList<>(); cmd.add("create-file-user"); cmd.add("--groups"); - cmd.add("g1"); + cmd.add(group); cmd.add("--passwordfile"); cmd.add(Paths.get("").toAbsolutePath() + "/src/test/resources/password.txt"); + cmd.add("--authrealmname"); + cmd.add(fileAuthRealmName); - cmd.add("u1"); + cmd.add(username); CliCommands.payaraGlassFish(cmd); } else { @@ -617,5 +623,44 @@ public static URL createClientTrustStore(WebClient webClient, URL base, String c webClient.getOptions().setSSLClientCertificate(new File(clientKeyStorePath).toURI().toURL(), "changeit", "jks"); return baseHttps; } + + public static URL getClientTrustStoreURL(URL baseHttps, String clientKeyStorePath) throws MalformedURLException { + // ### Ask the server for its certificate and add that to a new local trust store + // Server -> client : the trust store certificates are used to validate the certificate sent + // by the server + X509Certificate[] serverCertificateChain = getCertificateChainFromServer(baseHttps.getHost(), baseHttps.getPort()); + + if (!isEmpty(serverCertificateChain)) { + + System.out.println("Obtained certificate from server. Storing it in client trust store"); + + String trustStorePath = createTempJKSTrustStore(serverCertificateChain); + System.setProperty("javax.net.ssl.truststore", trustStorePath); + + System.out.println("Reading trust store from: " + trustStorePath); + return new File(trustStorePath).toURI().toURL(); + } else { + throw new IllegalStateException("Could not obtain certificates from server. Continuing without custom truststore"); + } + } + + public static KeyStore getKeyStore( + final URL keystoreURL, + final String keystorePassword, + final String keystoreType) { + + if (keystoreURL == null) { + return null; + } + + try { + final KeyStore keyStore = KeyStore.getInstance(keystoreType); + final char[] passwordChars = keystorePassword != null ? keystorePassword.toCharArray() : null; + keyStore.load(keystoreURL.openStream(), passwordChars); + return keyStore; + } catch (final IOException | KeyStoreException | NoSuchAlgorithmException | CertificateException ex) { + throw new RuntimeException(ex); + } + } } From 689a904b3ba17c41a1b32a7085f448b165bee4db Mon Sep 17 00:00:00 2001 From: Gaurav Gupta Date: Thu, 3 Oct 2019 14:13:32 +0530 Subject: [PATCH 07/15] PAYARA-3658 ejb-invoker endpoint - use existing ClientRequestFilter from Jersey --- .../payara/ejb/http/client/RemoteEJBContext.java | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContext.java b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContext.java index 9bfe18e51cb..36de04a7cb4 100644 --- a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContext.java +++ b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContext.java @@ -61,12 +61,14 @@ import java.util.concurrent.ExecutorService; import java.util.concurrent.ScheduledExecutorService; import java.util.logging.Logger; - import static fish.payara.ejb.http.client.RemoteEJBContextFactory.*; -import fish.payara.ejb.http.protocol.rs.BasicAuthFilter; import static java.util.concurrent.TimeUnit.MICROSECONDS; import java.util.logging.Level; +import javax.ws.rs.core.Form; import static javax.ws.rs.core.SecurityContext.BASIC_AUTH; +import static javax.ws.rs.core.SecurityContext.DIGEST_AUTH; +import static javax.ws.rs.core.SecurityContext.FORM_AUTH; +import org.glassfish.jersey.client.authentication.HttpAuthenticationFeature; /** * This is the context used for looking up and invoking remote EJBs via @@ -240,8 +242,10 @@ private ClientBuilder getClientBuilder() throws ClassNotFoundException, Instanti String providerCredentials = (String)environment.get(PROVIDER_CREDENTIALS); if (providerPrincipal != null && providerCredentials != null) { String authType = (String)environment.get(PROVIDER_AUTH_TYPE); - if (authType == null || BASIC_AUTH.equals(authType)) { - clientBuilder.register(new BasicAuthFilter(providerPrincipal, providerCredentials)); + if (null == authType || BASIC_AUTH.equals(authType)) { + clientBuilder.register(HttpAuthenticationFeature.basic(providerPrincipal, providerCredentials)); + } else if (DIGEST_AUTH.equals(authType)) { + clientBuilder.register(HttpAuthenticationFeature.digest(providerPrincipal, providerCredentials)); } } return clientBuilder; From 3a5dd52d93e2dca86341522b999bf788643b41e0 Mon Sep 17 00:00:00 2001 From: Gaurav Gupta Date: Thu, 3 Oct 2019 16:48:46 +0530 Subject: [PATCH 08/15] PAYARA-3658 ejb-invoker jax-rs client filter configuration --- .../ejb/http/client/RemoteEJBContext.java | 22 +++++++++++++++++++ .../http/client/RemoteEJBContextFactory.java | 2 ++ 2 files changed, 24 insertions(+) diff --git a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContext.java b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContext.java index 36de04a7cb4..0c19c0de8b1 100644 --- a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContext.java +++ b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContext.java @@ -64,6 +64,8 @@ import static fish.payara.ejb.http.client.RemoteEJBContextFactory.*; import static java.util.concurrent.TimeUnit.MICROSECONDS; import java.util.logging.Level; +import javax.ws.rs.client.ClientRequestFilter; +import javax.ws.rs.client.ClientResponseFilter; import javax.ws.rs.core.Form; import static javax.ws.rs.core.SecurityContext.BASIC_AUTH; import static javax.ws.rs.core.SecurityContext.DIGEST_AUTH; @@ -238,6 +240,26 @@ private ClientBuilder getClientBuilder() throws ClassNotFoundException, Instanti clientBuilder.withConfig(getInstance(environment.get(JAXRS_CLIENT_CONFIG), Configuration.class)); } + if (environment.containsKey(JAXRS_CLIENT_REQUEST_FILTER)) { + Object value = environment.get(JAXRS_CLIENT_REQUEST_FILTER); + if (value instanceof Class + && (ClientRequestFilter.class.isAssignableFrom((Class) value))) { + clientBuilder.register((Class) value); + } else if (value instanceof ClientRequestFilter) { + clientBuilder.register((ClientRequestFilter) value); + } + } + + if (environment.containsKey(JAXRS_CLIENT_RESPONSE_FILTER)) { + Object value = environment.get(JAXRS_CLIENT_RESPONSE_FILTER); + if (value instanceof Class + && (ClientResponseFilter.class.isAssignableFrom((Class) value))) { + clientBuilder.register((Class) value); + } else if (value instanceof ClientResponseFilter) { + clientBuilder.register((ClientResponseFilter) value); + } + } + String providerPrincipal = (String)environment.get(PROVIDER_PRINCIPAL); String providerCredentials = (String)environment.get(PROVIDER_CREDENTIALS); if (providerPrincipal != null && providerCredentials != null) { diff --git a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContextFactory.java b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContextFactory.java index 2b89a183df7..3a5af4f9133 100644 --- a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContextFactory.java +++ b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContextFactory.java @@ -76,6 +76,8 @@ public class RemoteEJBContextFactory implements InitialContextFactory { public static final String PROVIDER_PRINCIPAL = "fish.payara.provider.principal"; public static final String PROVIDER_CREDENTIALS = "fish.payara.provider.credentials"; + public static final String JAXRS_CLIENT_REQUEST_FILTER = "fish.payara.requestFilter"; + public static final String JAXRS_CLIENT_RESPONSE_FILTER = "fish.payara.responseFilter"; public static final String JAXRS_CLIENT_CONFIG = "fish.payara.withConfig"; public static final String JAXRS_CLIENT_TRUST_STORE = "fish.payara.trustStore"; public static final String JAXRS_CLIENT_SSL_CONTEXT = "fish.payara.sslContext"; From 4754497d0071e03554aafdef3ec7526575efeba3 Mon Sep 17 00:00:00 2001 From: Gaurav Gupta Date: Thu, 3 Oct 2019 16:52:13 +0530 Subject: [PATCH 09/15] PAYARA-3658 polish property name --- .../fish/payara/ejb/http/client/RemoteEJBContextFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContextFactory.java b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContextFactory.java index 3a5af4f9133..7ec79ae049e 100644 --- a/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContextFactory.java +++ b/appserver/ejb/ejb-http-remoting/client/src/main/java/fish/payara/ejb/http/client/RemoteEJBContextFactory.java @@ -72,7 +72,7 @@ public class RemoteEJBContextFactory implements InitialContextFactory { public static final String FACTORY_CLASS = RemoteEJBContextFactory.class.getName(); public static final String CLIENT_ADAPTER = "fish.payara.clientAdapter"; - public static final String PROVIDER_AUTH_TYPE = "fish.payara.provider.auth.type"; + public static final String PROVIDER_AUTH_TYPE = "fish.payara.provider.authType"; public static final String PROVIDER_PRINCIPAL = "fish.payara.provider.principal"; public static final String PROVIDER_CREDENTIALS = "fish.payara.provider.credentials"; From 0dea5e17bd48714da5d62f1ef70bbfd71a413e34 Mon Sep 17 00:00:00 2001 From: Gaurav Gupta Date: Fri, 4 Oct 2019 14:24:36 +0530 Subject: [PATCH 10/15] PAYARA-3658 ejb-invoker PR-Review changes - copyright & polish --- .../META-INF/services/javax.enterprise.inject.spi.Extension | 1 - .../src/main/java/fish/payara/ejb/invoke/InvokeEJBServlet.java | 3 +-- .../ejb/ejb-http-remoting/endpoint/src/main/webapp/error.xhtml | 2 +- .../ejb/ejb-http-remoting/endpoint/src/main/webapp/login.xhtml | 2 +- 4 files changed, 3 insertions(+), 5 deletions(-) delete mode 100644 appserver/ejb/ejb-http-remoting/admin/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension b/appserver/ejb/ejb-http-remoting/admin/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension deleted file mode 100644 index e705b463a08..00000000000 --- a/appserver/ejb/ejb-http-remoting/admin/src/main/resources/META-INF/services/javax.enterprise.inject.spi.Extension +++ /dev/null @@ -1 +0,0 @@ -fish.payara.ejb.http.admin.EjbInvokerExtension \ No newline at end of file diff --git a/appserver/ejb/ejb-http-remoting/endpoint/src/main/java/fish/payara/ejb/invoke/InvokeEJBServlet.java b/appserver/ejb/ejb-http-remoting/endpoint/src/main/java/fish/payara/ejb/invoke/InvokeEJBServlet.java index cd9fb3dff45..f63df4fe9e1 100644 --- a/appserver/ejb/ejb-http-remoting/endpoint/src/main/java/fish/payara/ejb/invoke/InvokeEJBServlet.java +++ b/appserver/ejb/ejb-http-remoting/endpoint/src/main/java/fish/payara/ejb/invoke/InvokeEJBServlet.java @@ -71,8 +71,6 @@ import java.util.Base64; import java.util.logging.Level; import java.util.logging.Logger; -import javax.inject.Inject; - import static javax.naming.Context.SECURITY_CREDENTIALS; import static javax.naming.Context.SECURITY_PRINCIPAL; import static javax.servlet.http.HttpServletResponse.SC_INTERNAL_SERVER_ERROR; @@ -93,6 +91,7 @@ public class InvokeEJBServlet extends HttpServlet { private String[] roles; + @Override public void init() throws ServletException { EjbInvokerConfiguration config = Globals.getDefaultBaseServiceLocator() .getService(EjbInvokerConfiguration.class); diff --git a/appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/error.xhtml b/appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/error.xhtml index 6caa8214973..a6a99befea2 100644 --- a/appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/error.xhtml +++ b/appserver/ejb/ejb-http-remoting/endpoint/src/main/webapp/error.xhtml @@ -2,7 +2,7 @@ - + ejb-http-remoting ejb-invoker-secure-endpoint diff --git a/nucleus/admin/template/pom.xml b/nucleus/admin/template/pom.xml index 5837cf46cd5..ef6c0b3a2f7 100644 --- a/nucleus/admin/template/pom.xml +++ b/nucleus/admin/template/pom.xml @@ -104,7 +104,7 @@ ${project.version} war false - ${project.build.directory}/endpoints/ejb-invoker + ${project.build.directory}/endpoints/__ejb-invoker From 665f72ef54b068cfe177c6c820c0db2f5fc74adb Mon Sep 17 00:00:00 2001 From: Gaurav Gupta Date: Thu, 10 Oct 2019 10:45:38 +0530 Subject: [PATCH 12/15] PAYARA-3658 ejb-invoker PR-Review changes - add restart server warning --- .../ejb/http/admin/EjbInvokerService.java | 18 +++++++++++++++++- .../SetEjbInvokerConfigurationCommand.java | 2 ++ 2 files changed, 19 insertions(+), 1 deletion(-) diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerService.java b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerService.java index e0994d5fd14..390dabc7b07 100644 --- a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerService.java +++ b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerService.java @@ -46,6 +46,9 @@ import com.sun.enterprise.deployment.web.LoginConfiguration; import com.sun.enterprise.util.StringUtils; import static fish.payara.ejb.http.admin.Constants.EJB_INVOKER_APP; +import java.beans.PropertyChangeEvent; +import java.util.ArrayList; +import java.util.List; import javax.annotation.PostConstruct; import javax.inject.Inject; import static javax.servlet.http.HttpServletRequest.FORM_AUTH; @@ -58,13 +61,16 @@ import org.glassfish.internal.deployment.Deployment; import org.glassfish.web.deployment.runtime.SunWebAppImpl; import org.jvnet.hk2.annotations.Service; +import org.jvnet.hk2.config.ConfigListener; +import org.jvnet.hk2.config.UnprocessedChangeEvent; +import org.jvnet.hk2.config.UnprocessedChangeEvents; /** * * @author Gaurav Gupta */ @Service(name = "ejb-invoker-service") @RunLevel(StartupRunLevel.VAL) -public class EjbInvokerService implements EventListener { +public class EjbInvokerService implements EventListener, ConfigListener { @Inject private Events events; @@ -118,4 +124,14 @@ public void event(EventListener.Event event) { } } } + + @Override + public UnprocessedChangeEvents changed(PropertyChangeEvent[] events) { + List unchangedList = new ArrayList<>(); + for (PropertyChangeEvent event : events) { + unchangedList.add(new UnprocessedChangeEvent(event, "EJB Invoker configuration changed:" + event.getPropertyName() + + " was changed from " + event.getOldValue() + " to " + event.getNewValue())); + } + return new UnprocessedChangeEvents(unchangedList); + } } diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/SetEjbInvokerConfigurationCommand.java b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/SetEjbInvokerConfigurationCommand.java index bf258b12aa2..ac72452f3ef 100644 --- a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/SetEjbInvokerConfigurationCommand.java +++ b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/SetEjbInvokerConfigurationCommand.java @@ -238,6 +238,8 @@ public void execute(AdminCommandContext context) { } else { disableEjbInvoker(actionReport); } + } else { + actionReport.setMessage("Restart server or re-enable the ejb-invoker service for the change to take effect."); } // If everything has passed, scrap the subaction reports as we don't want to print them out From 171cf80a91a99cd561b1843a5a858040eae0bdd2 Mon Sep 17 00:00:00 2001 From: Gaurav Gupta Date: Fri, 11 Oct 2019 11:07:58 +0530 Subject: [PATCH 13/15] PAYARA-3658 ejb-invoker PR-Review changes - filter UnprocessedChangeEvent --- .../java/fish/payara/ejb/http/admin/EjbInvokerService.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerService.java b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerService.java index 390dabc7b07..6b096095c77 100644 --- a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerService.java +++ b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerService.java @@ -129,9 +129,14 @@ public void event(EventListener.Event event) { public UnprocessedChangeEvents changed(PropertyChangeEvent[] events) { List unchangedList = new ArrayList<>(); for (PropertyChangeEvent event : events) { + if ("enabled".equals(event.getPropertyName())){ + unchangedList.clear(); + break; + } unchangedList.add(new UnprocessedChangeEvent(event, "EJB Invoker configuration changed:" + event.getPropertyName() + " was changed from " + event.getOldValue() + " to " + event.getNewValue())); } - return new UnprocessedChangeEvents(unchangedList); + return (unchangedList.size() > 0) + ? new UnprocessedChangeEvents(unchangedList) : null; } } From 5b33ef0e092cf2f87334a336027e37aefcead7cd Mon Sep 17 00:00:00 2001 From: Gaurav Gupta Date: Tue, 15 Oct 2019 23:37:26 +0530 Subject: [PATCH 14/15] PAYARA-3658 ejb-invoker PR-Review changes - filter disabled UnprocessedChangeEvent --- .../fish/payara/ejb/http/admin/EjbInvokerService.java | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerService.java b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerService.java index 6b096095c77..467c367271a 100644 --- a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerService.java +++ b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/EjbInvokerService.java @@ -39,7 +39,6 @@ */ package fish.payara.ejb.http.admin; -import com.sun.enterprise.config.serverbeans.SecurityService; import com.sun.enterprise.deployment.Application; import com.sun.enterprise.deployment.WebBundleDescriptor; import static com.sun.enterprise.deployment.runtime.web.SunWebApp.HTTPSERVLET_SECURITY_PROVIDER; @@ -75,9 +74,6 @@ public class EjbInvokerService implements EventListener, ConfigListener { @Inject private Events events; - @Inject - private SecurityService securityService; - @Inject private EjbInvokerConfiguration config; @@ -128,12 +124,16 @@ public void event(EventListener.Event event) { @Override public UnprocessedChangeEvents changed(PropertyChangeEvent[] events) { List unchangedList = new ArrayList<>(); + if(!Boolean.parseBoolean(config.getEnabled())) { + return null; + } for (PropertyChangeEvent event : events) { if ("enabled".equals(event.getPropertyName())){ unchangedList.clear(); break; } - unchangedList.add(new UnprocessedChangeEvent(event, "EJB Invoker configuration changed:" + event.getPropertyName() + unchangedList.add(new UnprocessedChangeEvent(event, + "EJB Invoker configuration changed: " + event.getPropertyName() + " was changed from " + event.getOldValue() + " to " + event.getNewValue())); } return (unchangedList.size() > 0) From 52bfc8f8bf36f9f8125f40d244f13c81bde5841e Mon Sep 17 00:00:00 2001 From: Gaurav Gupta Date: Wed, 23 Oct 2019 14:05:57 +0530 Subject: [PATCH 15/15] PAYARA-3658 skip command-line warning if service not enabled --- .../ejb/http/admin/SetEjbInvokerConfigurationCommand.java | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/SetEjbInvokerConfigurationCommand.java b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/SetEjbInvokerConfigurationCommand.java index ac72452f3ef..eb53c150e7d 100644 --- a/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/SetEjbInvokerConfigurationCommand.java +++ b/appserver/ejb/ejb-http-remoting/admin/src/main/java/fish/payara/ejb/http/admin/SetEjbInvokerConfigurationCommand.java @@ -198,8 +198,7 @@ public void execute(AdminCommandContext context) { actionReport.failure(LOGGER, "Failed to update EJB Invoker configuration", ex); } - if (Boolean.parseBoolean(config.getEnabled()) - && Boolean.parseBoolean(config.getSecurityEnabled())) { + if (Boolean.parseBoolean(config.getSecurityEnabled())) { // If the required message security provider is not present, create it if (StringUtils.ok(config.getAuthModuleClass())) { @@ -238,7 +237,7 @@ public void execute(AdminCommandContext context) { } else { disableEjbInvoker(actionReport); } - } else { + } else if(Boolean.parseBoolean(config.getEnabled())) { actionReport.setMessage("Restart server or re-enable the ejb-invoker service for the change to take effect."); }