com.sun.enterprise.security.jauth.jaspic.provider.config.PipeHelper Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of payara-micro Show documentation
Show all versions of payara-micro Show documentation
Micro Distribution of the Payara Project
/*
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
*
* Copyright (c) 1997-2013 Oracle and/or its affiliates. All rights reserved.
*
* The contents of this file are subject to the terms of either the GNU
* General Public License Version 2 only ("GPL") or the Common Development
* and Distribution License("CDDL") (collectively, the "License"). You
* may not use this file except in compliance with the License. You can
* obtain a copy of the License at
* https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
* or packager/legal/LICENSE.txt. See the License for the specific
* language governing permissions and limitations under the License.
*
* When distributing the software, include this License Header Notice in each
* file and include the License file at packager/legal/LICENSE.txt.
*
* GPL Classpath Exception:
* Oracle designates this particular file as subject to the "Classpath"
* exception as provided by Oracle in the GPL Version 2 section of the License
* file that accompanied this code.
*
* Modifications:
* If applicable, add the following below the License Header, with the fields
* enclosed by brackets [] replaced by your own identifying information:
* "Portions Copyright [year] [name of copyright owner]"
*
* Contributor(s):
* If you wish your version of this file to be governed by only the CDDL or
* only the GPL Version 2, indicate your decision by adding "[Contributor]
* elects to include this software in this distribution under the [CDDL or GPL
* Version 2] license." If you don't indicate a single choice of license, a
* recipient has the option to distribute your version of this file under
* either the CDDL, the GPL Version 2 or to extend the choice of license to
* its licensees as provided above. However, if you add GPL Version 2 code
* and therefore, elected the GPL Version 2 license, then the option applies
* only if the new code is made subject to such option by the copyright
* holder.
*/
// Portions Copyright [2018-2021] [Payara Foundation and/or its affiliates]
package com.sun.enterprise.security.jauth.jaspic.provider.config;
import static com.sun.enterprise.security.jaspic.AuthMessagePolicy.getMessageSecurityBinding;
import static com.sun.enterprise.security.webservices.PipeConstants.BINDING;
import static com.sun.enterprise.security.webservices.PipeConstants.ENDPOINT;
import static com.sun.enterprise.security.webservices.PipeConstants.SEI_MODEL;
import static com.sun.enterprise.security.webservices.PipeConstants.SERVICE_ENDPOINT;
import static com.sun.enterprise.security.webservices.PipeConstants.SOAP_LAYER;
import static com.sun.xml.ws.api.SOAPVersion.SOAP_11;
import java.lang.reflect.Method;
import java.net.URL;
import java.security.AccessController;
import java.security.PrivilegedActionException;
import java.security.PrivilegedExceptionAction;
import java.util.Map;
import javax.security.auth.Subject;
import javax.security.auth.callback.CallbackHandler;
import jakarta.security.auth.message.AuthException;
import jakarta.security.auth.message.AuthStatus;
import jakarta.security.auth.message.MessageInfo;
import jakarta.security.auth.message.config.ClientAuthConfig;
import jakarta.security.auth.message.config.ClientAuthContext;
import jakarta.security.auth.message.config.ServerAuthConfig;
import jakarta.security.auth.message.config.ServerAuthContext;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.xml.bind.UnmarshalException;
import jakarta.xml.ws.WebServiceException;
import jakarta.xml.ws.handler.MessageContext;
import org.glassfish.api.invocation.ComponentInvocation;
import org.glassfish.api.invocation.InvocationManager;
import org.glassfish.deployment.common.ModuleDescriptor;
import org.glassfish.internal.api.Globals;
import com.sun.enterprise.deployment.Application;
import com.sun.enterprise.deployment.BundleDescriptor;
import com.sun.enterprise.deployment.EjbDescriptor;
import com.sun.enterprise.deployment.ServiceReferenceDescriptor;
import com.sun.enterprise.deployment.WebBundleDescriptor;
import com.sun.enterprise.deployment.WebServiceEndpoint;
import com.sun.enterprise.deployment.runtime.common.MessageSecurityBindingDescriptor;
import com.sun.enterprise.security.SecurityContext;
import com.sun.enterprise.security.SecurityServicesUtil;
import com.sun.enterprise.security.audit.AuditManager;
import com.sun.enterprise.security.common.AppservAccessController;
import com.sun.enterprise.security.common.ClientSecurityContext;
import com.sun.enterprise.security.ee.audit.AppServerAuditManager;
import com.sun.enterprise.security.ee.authorize.EJBPolicyContextDelegate;
import com.sun.enterprise.security.jaspic.WebServicesDelegate;
import com.sun.enterprise.security.jaspic.config.GFServerConfigProvider;
import com.sun.enterprise.security.jaspic.config.HandlerContext;
import com.sun.enterprise.security.jaspic.config.PayaraJaspicServices;
import com.sun.enterprise.security.webservices.PipeConstants;
import com.sun.enterprise.util.LocalStringManagerImpl;
import com.sun.enterprise.util.io.FileUtils;
import com.sun.xml.ws.api.EndpointAddress;
import com.sun.xml.ws.api.SOAPVersion;
import com.sun.xml.ws.api.WSBinding;
import com.sun.xml.ws.api.message.Message;
import com.sun.xml.ws.api.message.Messages;
import com.sun.xml.ws.api.message.Packet;
import com.sun.xml.ws.api.model.JavaMethod;
import com.sun.xml.ws.api.model.SEIModel;
import com.sun.xml.ws.api.model.wsdl.WSDLPort;
import com.sun.xml.ws.api.server.WSEndpoint;
public class PipeHelper extends PayaraJaspicServices {
protected static final LocalStringManagerImpl localStrings = new LocalStringManagerImpl(PipeConstants.class);
private AppServerAuditManager auditManager;
private boolean isEjbEndpoint;
private SEIModel seiModel;
private SOAPVersion soapVersion;
private InvocationManager invManager;
private EJBPolicyContextDelegate ejbDelegate;
public PipeHelper(String layer, Map properties, CallbackHandler callbackHandler) {
init(layer, getAppCtxt(properties), properties, callbackHandler, Globals.get(WebServicesDelegate.class));
isEjbEndpoint = processSunDeploymentDescriptor();
seiModel = (SEIModel) properties.get(SEI_MODEL);
WSBinding binding = (WSBinding) properties.get(BINDING);
if (binding == null) {
WSEndpoint endPoint = (WSEndpoint) properties.get(ENDPOINT);
if (endPoint != null) {
binding = endPoint.getBinding();
}
}
soapVersion = binding != null ? binding.getSOAPVersion() : SOAP_11;
AuditManager am = SecurityServicesUtil.getInstance() != null ? SecurityServicesUtil.getInstance().getAuditManager() : null;
auditManager = am instanceof AppServerAuditManager ? (AppServerAuditManager) am : new AppServerAuditManager();// workaround
// habitat
invManager = SecurityServicesUtil.getInstance() != null
? SecurityServicesUtil.getInstance().getHabitat().getService(InvocationManager.class)
: null;
this.ejbDelegate = new EJBPolicyContextDelegate();
}
@Override
public ClientAuthContext getClientAuthContext(MessageInfo info, Subject subject) throws AuthException {
ClientAuthConfig clientConfig = (ClientAuthConfig) getAuthConfig(false);
if (clientConfig == null) {
return null;
}
addModel(info, map);
return clientConfig.getAuthContext(clientConfig.getAuthContextID(info), subject, map);
}
@Override
public ServerAuthContext getServerAuthContext(MessageInfo info, Subject subject) throws AuthException {
ServerAuthConfig serverConfig = (ServerAuthConfig) getAuthConfig(true);
if (serverConfig == null) {
return null;
}
addModel(info, map);
addPolicy(info, map);
return serverConfig.getAuthContext(serverConfig.getAuthContextID(info), subject, map);
}
public static Subject getClientSubject() {
Subject subject = null;
if (SecurityServicesUtil.getInstance() == null || SecurityServicesUtil.getInstance().isACC()) {
ClientSecurityContext clientSecurityContext = ClientSecurityContext.getCurrent();
if (clientSecurityContext != null) {
subject = clientSecurityContext.getSubject();
}
if (subject == null) {
subject = Subject.getSubject(AccessController.getContext());
}
} else {
SecurityContext securityContext = SecurityContext.getCurrent();
if (securityContext != null && !securityContext.didServerGenerateCredentials()) {
// make sure we don't use default unauthenticated subject,
// so that module cannot change this important (constant)
// subject.
subject = securityContext.getSubject();
}
}
if (subject == null) {
subject = new Subject();
}
return subject;
}
public void getSessionToken(Map map, MessageInfo info, Subject subject) throws AuthException {
ClientAuthConfig clientAuthConfig = (ClientAuthConfig) getAuthConfig(false);
if (clientAuthConfig != null) {
map.putAll(map);
addModel(info, map);
clientAuthConfig.getAuthContext(clientAuthConfig.getAuthContextID(info), subject, map);
}
}
public void authorize(Packet request) throws Exception {
// SecurityContext constructor should set initiator to
// unathenticated if Subject is null or empty
Subject s = (Subject) request.invocationProperties.get(PipeConstants.CLIENT_SUBJECT);
if (s == null || (s.getPrincipals().isEmpty() && s.getPublicCredentials().isEmpty())) {
SecurityContext.setUnauthenticatedContext();
} else {
SecurityContext sC = new SecurityContext(s);
SecurityContext.setCurrent(sC);
}
// we should try to replace this endpoint specific
// authorization check with a generic web service message check
// and move the endpoint specific check down stream
if (isEjbEndpoint) {
if (invManager == null) {
throw new RuntimeException(localStrings.getLocalString("enterprise.webservice.noEjbInvocationManager",
"Cannot validate request : invocation manager null for EJB WebService"));
}
ComponentInvocation inv = (ComponentInvocation) invManager.getCurrentInvocation();
// one need to copy message here, otherwise the message may be
// consumed
if (ejbDelegate != null) {
ejbDelegate.setSOAPMessage(request.getMessage(), inv);
}
Exception ie;
Method m = null;
if (seiModel != null) {
JavaMethod jm = request.getMessage().getMethod(seiModel);
m = (jm != null) ? jm.getMethod() : null;
} else { // WebServiceProvider
WebServiceEndpoint endpoint = (WebServiceEndpoint) map.get(PipeConstants.SERVICE_ENDPOINT);
EjbDescriptor ejbDescriptor = endpoint.getEjbComponentImpl();
if (ejbDescriptor != null) {
final String ejbImplClassName = ejbDescriptor.getEjbImplClassName();
if (ejbImplClassName != null) {
try {
m = (Method) AppservAccessController.doPrivileged(new PrivilegedExceptionAction() {
@Override
public Object run() throws Exception {
ClassLoader loader = Thread.currentThread().getContextClassLoader();
Class clazz = Class.forName(ejbImplClassName, true, loader);
return clazz.getMethod("invoke", new Class[] { Object.class });
}
});
} catch (PrivilegedActionException pae) {
throw new RuntimeException(pae.getException());
}
}
}
}
if (m != null) {
if (ejbDelegate != null) {
try {
if (!ejbDelegate.authorize(inv, m)) {
throw new Exception(localStrings.getLocalString("enterprise.webservice.methodNotAuth",
"Client not authorized for invocation of {0}", new Object[] { m }));
}
} catch (UnmarshalException e) {
String errorMsg = localStrings.getLocalString("enterprise.webservice.errorUnMarshalMethod",
"Error unmarshalling method for ejb {0}", new Object[] { ejbName() });
ie = new UnmarshalException(errorMsg);
ie.initCause(e);
throw ie;
} catch (Exception e) {
ie = new Exception(localStrings.getLocalString("enterprise.webservice.methodNotAuth",
"Client not authorized for invocation of {0}", new Object[] { m }));
ie.initCause(e);
throw ie;
}
}
}
}
}
public void auditInvocation(Packet request, AuthStatus status) {
if (auditManager.isAuditOn()) {
String uri = null;
if (!isEjbEndpoint && request != null && request.supports(MessageContext.SERVLET_REQUEST)) {
HttpServletRequest httpServletRequest = (HttpServletRequest) request.get(MessageContext.SERVLET_REQUEST);
uri = httpServletRequest.getRequestURI();
}
String endpointName = null;
if (map != null) {
WebServiceEndpoint endpoint = (WebServiceEndpoint) map.get(PipeConstants.SERVICE_ENDPOINT);
if (endpoint != null) {
endpointName = endpoint.getEndpointName();
}
}
if (endpointName == null) {
endpointName = "(no endpoint)";
}
if (isEjbEndpoint) {
auditManager.ejbAsWebServiceInvocation(endpointName, AuthStatus.SUCCESS.equals(status));
} else {
auditManager.webServiceInvocation(((uri == null) ? "(no uri)" : uri), endpointName, AuthStatus.SUCCESS.equals(status));
}
}
}
public Object getModelName() {
WSDLPort wsdlModel = (WSDLPort) getProperty(PipeConstants.WSDL_MODEL);
return (wsdlModel == null ? "unknown" : wsdlModel.getName());
}
@Deprecated // should be unused, but left for compilation
public void addModelAndPolicy(Packet request) {
}
// always returns response with embedded fault
// public static Packet makeFaultResponse(Packet response, Throwable t) {
public Packet makeFaultResponse(Packet response, Throwable t) {
// wrap throwable in WebServiceException, if necessary
if (!(t instanceof WebServiceException)) {
t = (Throwable) new WebServiceException(t);
}
if (response == null) {
response = new Packet();
}
// try to create fault in provided response packet, if an exception
// is thrown, create new packet, and create fault in it.
try {
return response.createResponse(Messages.create(t, this.soapVersion));
} catch (Exception e) {
response = new Packet();
}
return response.createResponse(Messages.create(t, this.soapVersion));
}
public boolean isTwoWay(boolean twoWayIsDefault, Packet request) {
boolean twoWay = twoWayIsDefault;
Message m = request.getMessage();
if (m != null) {
WSDLPort wsdlModel = (WSDLPort) getProperty(PipeConstants.WSDL_MODEL);
if (wsdlModel != null) {
twoWay = (m.isOneWay(wsdlModel) ? false : true);
}
}
return twoWay;
}
// returns empty response if request is determined to be one-way
public Packet getFaultResponse(Packet request, Packet response, Throwable t) {
boolean twoWay = true;
try {
twoWay = isTwoWay(true, request);
} catch (Exception e) {
// exception is consumed, and twoWay is assumed
}
if (twoWay) {
return makeFaultResponse(response, t);
} else {
return new Packet();
}
}
@Override
public void disable() {
getRegistrationWrapper().disableWithRefCount();
}
@Override
protected HandlerContext getHandlerContext(Map map) {
String realmName = null;
WebServiceEndpoint wSE = (WebServiceEndpoint) map.get(PipeConstants.SERVICE_ENDPOINT);
if (wSE != null) {
Application app = wSE.getBundleDescriptor().getApplication();
if (app != null) {
realmName = app.getRealm();
}
if (realmName == null) {
realmName = wSE.getRealm();
}
}
final String fRealmName = realmName;
return new HandlerContext() {
@Override
public String getRealmName() {
return fRealmName;
}
};
}
private boolean processSunDeploymentDescriptor() {
if (factory == null) {
return false;
}
MessageSecurityBindingDescriptor binding = getMessageSecurityBinding(SOAP_LAYER, map);
if (binding != null) {
if (!hasExactMatchAuthProvider()) {
String jaspicProviderRegisID = factory.registerConfigProvider(
new GFServerConfigProvider(null, null),
layer, appCtxt, "GF AuthConfigProvider bound by Sun Specific Descriptor");
setRegistrationId(jaspicProviderRegisID);
}
}
WebServiceEndpoint webServiceEndpoint = (WebServiceEndpoint) map.get(SERVICE_ENDPOINT);
return webServiceEndpoint == null ? false : webServiceEndpoint.implementedByEjbComponent();
}
private static String getAppCtxt(Map map) {
String rvalue;
WebServiceEndpoint wse = (WebServiceEndpoint) map.get(SERVICE_ENDPOINT);
// endpoint
if (wse != null) {
rvalue = getServerName(wse) + " " + getEndpointURI(wse);
// client reference
} else {
ServiceReferenceDescriptor srd = (ServiceReferenceDescriptor) map.get(PipeConstants.SERVICE_REF);
rvalue = getClientModuleID(srd) + " " + getRefName(srd, map);
}
return rvalue;
}
private static String getServerName(WebServiceEndpoint wse) {
// XXX FIX ME: need to lookup real hostname
String hostname = "localhost";
return hostname;
}
private static String getRefName(ServiceReferenceDescriptor srd, Map map) {
String name = null;
if (srd != null) {
name = srd.getName();
}
if (name == null) {
EndpointAddress ea = (EndpointAddress) map.get(PipeConstants.ENDPOINT_ADDRESS);
if (ea != null) {
URL url = ea.getURL();
if (url != null) {
name = url.toString();
}
}
}
if (name == null) {
name = "#default-ref-name#";
}
return name;
}
private static String getEndpointURI(WebServiceEndpoint wse) {
String uri = "#default-endpoint-context#";
if (wse != null) {
uri = wse.getEndpointAddressUri();
if (uri != null && (!uri.startsWith("/"))) {
uri = "/" + uri;
}
if (wse.implementedByWebComponent()) {
WebBundleDescriptor wbd = (WebBundleDescriptor) wse.getBundleDescriptor();
if (wbd != null) {
String contextRoot = wbd.getContextRoot();
if (contextRoot != null) {
if (!contextRoot.startsWith("/")) {
contextRoot = "/" + contextRoot;
}
uri = contextRoot + uri;
}
}
}
}
return uri;
}
private static String getClientModuleID(ServiceReferenceDescriptor srd) {
String rvalue = "#default-client-context#";
if (srd != null) {
ModuleDescriptor md = null;
BundleDescriptor bd = (BundleDescriptor) srd.getBundleDescriptor();
if (bd != null) {
md = bd.getModuleDescriptor();
}
Application a = (bd == null) ? null : bd.getApplication();
if (a != null) {
if (a.isVirtual()) {
rvalue = a.getRegistrationName();
} else if (md != null) {
rvalue = FileUtils.makeFriendlyFilename(md.getArchiveUri());
}
} else if (md != null) {
rvalue = FileUtils.makeFriendlyFilename(md.getArchiveUri());
}
}
return rvalue;
}
private static void addModel(MessageInfo info, Map map) {
Object model = map.get(PipeConstants.WSDL_MODEL);
if (model != null) {
info.getMap().put(PipeConstants.WSDL_MODEL, model);
}
}
private static void addPolicy(MessageInfo info, Map map) {
Object pol = map.get(PipeConstants.POLICY);
if (pol != null) {
info.getMap().put(PipeConstants.POLICY, pol);
}
}
private String ejbName() {
WebServiceEndpoint wSE = (WebServiceEndpoint) getProperty(PipeConstants.SERVICE_ENDPOINT);
return (wSE == null ? "unknown" : wSE.getEjbComponentImpl().getName());
}
}