Globus Toolkit 3.9.2 Development Documentation: WS Authentication & Authorization
Service-side Message Level Security
Please report any errors or suggestions to our Bugzilla system.
- Introduction
- Security Descriptor
- Secure Resources
- Useful Security API
- Other Features
- Container-only Security Configuration
- Secure Notifications
- Limitations
- Errors
1. Introduction
Security can be set at container level, service level or resource level, using a security descriptor to specify the desired security properties. Not all properties can be set at each level, but typically, the security property value is obtained by looking for property presence in this order: resource level property, service level property and then container level property. If not set, defaults are used in some cases and errors are reported in other cases.
For container and service level security, no code modifications are necessary in general, and can be set using a security descriptor. However, minor code modifications might be needed for specialized purposes, such as setting the service owner with the caller's delegated credential (e.g. in cases where a service is supposed to be accessed only by a specific user -- the user that created it.)
In the case of security descriptor for secure resources, code modifications need to be done as described in Section 3, but the descriptor can be read from a file as well.
No changes to the WSDL are required for configuring security.
2. Security Descriptor
Security descriptors contain various security properties like credentials, gridmap, required authentication and authorization and so on. There are three kinds of security descriptors in the code base for setting container, service and resource security properties, respectively:
- service security descriptor
- container security descriptor
- resource security descriptor
Each of these are represented as objects in the code base and can be altered programmatically. Service and container security descriptors can be configured as an XML file in the deployment descriptor (server-config.wsdd) as shown below. Resource security descriptors can only be created dynamically either programmatically or from a descriptor file. Secure resources have been described in detail in Section 3.
Configuring service and container descriptor files:<globalConfiguration>
...
<parameter name="containerSecDesc" value="org/wsrf/impl/security/container-security-config.xml">
...
<globalConfiguration>
...
<service name="my/dummy/service" provider="Handler" style="wrapped">
...
<parameter name="securityDescriptor" value="org/globus/wsrf/impl/security/descriptor/security-config.xml"/>
...
</service>
It is loaded in the same way as any other resource data, i.e. from the class path. This allows the security descriptor to be included in the same .jar file as the rest of the service code. The security deployment descriptor will not be reloaded if it is changed at runtime.
The security descriptor files need to comply with the service
security descriptor schema or container
security descriptor schema as appropriate. The resource security descriptor
file uses the same schema as the service security descriptor. The security
deployment descriptor is contained within the <securityConfig xmlns="http://www.globus.org"> element.
2.1 Writing security descriptor files
The next few sections deal with writing security descriptor files to set various properties. Please note that not all parameters are applicable for all three types of descriptors and are appropriately noted in the relevant sections. The few parameters relevant only for container security descriptor are described in Section 6.
2.1.1 Configuring credentials
The container and each service can also be configured with a separate set of credentials. You can set the credentials using either the a) path to a proxy file or b) path to a certificate and key file. This is done by adding the following block to the container or service security descriptor.
Example for option (a):<securityConfig xmlns="http://www.globus.org">Example for option (b):
...
<credential>
<key-file value="keyFile"/>
<cert-file value="certFile"/>
</credential>
...
</securityConfig><securityConfig xmlns="http://www.globus.org">
...
<proxy-file value="proxyFile"/>
...
</securityConfig>The service will look for credentials in this order:
- Resource credentials
- Service credentials
- Container credentials
- Default credentials (uses the underlying security library to acquire the credentials, which will be the proxy certificate of the user that is running the container)
If the configured credentials files change while the container is running, they will be automatically reloaded.
2.1.2 Configuring gridmap
The container and each service can be configured with a separate gridmap in its security descriptor:
<securityConfig xmlns="http://www.globus.org">
...
<gridmap value="gridMapFile"/>
...
</securityConfig>The service will look for gridmap configured first in resource, then service and then container.
For services configured to perform gridmap file authorization, the gridmap file can be updated dynamically using the SecurityManager API. Also, if the gridmap file changes at runtime it will be automatically reloaded.
2.1.3 Configuring Authentication Methods
This can only be done at service or resource level.
The authentication methods a service requires are specified using the
<auth-method>element. The authentication methods can also be configured on a per method basis. This is done by specifying the<auth-method>element within the<method name="qname">elements. The name attribute of the element can just be the operation name (preferred) or the operation name with a given namespace.Currently, the following authentication methods are supported:
<none/>Indicates that no authentication is required.
This method cannot be specified with any other authentication method.
<GSISecureMessage/>Indicates the GSI Secure Message authentication method (
<pkey>may also be used.)The
<protection-level>sub element can be used to specify a specific protection level that must be applied to the message:<integrity/>Indicates that the message must be integrity protected (signed.) <privacy/>Indicates that the message must be privacy protected (encrypted & signed.) <GSISecureConversation/>Indicates the GSI Secure Conversation authentication method (with integrity or privacy protection)
<gsi>may also be used.The
<protection-level>sub element can be used to indicate a specific protection level that must be applied to the message:<integrity/>Indicates that the message must be integrity protected (signed.) <privacy/>Indicates that the message must be privacy protected (signed & encrypted.) Notes:
- Multiple authentication methods can be specified under the
<auth-method>element (expect for the<none/>method, see above.) As long as one of the authentication methods is performed, the access to the service is allowed.
- If no
<protection-level>sub element is specified, then all protection levels are available to clients. However, if the<protection-level>sub element is specified, then the service will only accept the protection levels listed under said element.
- The
org.globus.wsrf.impl.security.authentication.SecurityPolicyHandlerhandler must be installed properly in order for this to work. This handler is installed by default.
- If a security deployment descriptor is not specified, authentication method enforcement is not performed.
Example:
<securityConfig xmlns="http://www.globus.org">
<method name="findServiceData">
<auth-method>
<none/>
</auth-method>
</method>
<method name="destroy">
<auth-method>
<GSISecureMessage/>
<GSISecureConversation>
<protection-level>
<integrity/>
</protection-level>
</GSISecureConversation>
</auth-method>
</method>
<!-- default auth-method for any other method -->
<auth-method>
<GSISecureConversation/>
</auth-method>
</securityConfig>In the above example:
- the
findServiceData()operation does not require any authentication
- the
destroy()operation requires either GSI Secure Message authentication with either level of protection or GSI Secure Conversation authentication with integrity protection.
- all other operations must be authenticated with GSI Secure Conversation with either level of protection.
2.1.4 Configuring run-as mode
The
<run-as>element is used to configure the JAAS run-as identity under which the service method will be executed. The run-as identity can be configured on a per method basis. Currently, the following run-as identities are supported:
<caller-identity/>The service method will be run with the security identity of the client. The caller Subject will contain the following:
- If using GSI Secure Message: a GlobusPrincipal (the identity of the signer) is added to the principal set of the caller-identity Subject. Also, the signer's certificate chain is added to the public credentials set of the Subject object.
- If using GSI Secure Conversation: a GlobusPrincipal (the identity of the initiator) is added to the principal set of the Subject.
- If client authentication was performed, the client's certificate chain will be added to the public credentials set of the Subject object.
- Also, if delegation was performed, the delegated credential is added to the private credential set of the Subject object.
- If gridmap file authorization was performed, a UserNamePrincipal is added to the principal set of the Subject object
<system-identity/>The service method will be run with the security identity of the container. <service-identity/>The service method will be run with the security identity of the service itself (if the service has one, otherwise the container identity will be used.) <resource-identity/>The service method will be run with the security identity of the resource. If no resource is specified or it does not have a configured subject, credential in this order of occurentce will be used: service credential, container credential. Notes:
- service-identity is the default setting.
- The
org.globus.wsrf.impl.security.authentication.SecurityPolicyHandlerhandler must be installed properly in order for this to work.
- If the security deployment descriptor is not specified, then the run-as identity is not set and there will be no JAAS subject associated with the execution of the operation. This means that any method calls that require credentials and that are invoked by the service method itself will fail.
Example:
<securityConfig xmlns="http://www.globus.org">
<method name="counter:add" xmlns:counter="http://www.globus.org/samples/counter">
<run-as>
<caller-identity/>
</run-as>
</method>
<method name="counter:subtract" xmlns:ogsi="http://www.globus.org/samples/counter">
<run-as>
<system-identity/>
</run-as>
</method>
<!-- default run-as for any other method -->
<run-as>
<service-identity/>
</run-as>
</securityConfig>In the above example:
- the
add()operation will be run with the caller's identity
- the
subtract()call will be run with the system identity
- all other operations will be run with the service identity (if the service has one set.)
2.1.5 Configuring an authorization mechanism
The container and each service can be configured with a separate authorization mechanism using the element
<authz value="someMethod"/>. Currently the following authorization mechanisms are supported:
noneNo authorization is performed. selfOnly the clients with the same identity as the identity in the current JAAS subject associated with the service are allowed to access the service.
The identity in the JAAS subject is determined through the value in the run-as element in the service security deployment descriptor (see Configuring run-as mode.)
gridmapGridmap file authorization is performed. A gridmap file must be configured as described in Section 2.1.2. customA custom authorization mechanism is configured using the element:
<authzClass value="customAuthzClassname"/>where
valueequals the fully qualified name of the custom authorization class that needs to be used.Refer to Section 5.2 for details on writing a custom authorization mechanism
Example:
<securityConfig xmlns="http://www.globus.org">
...
<authz value="custom"/>
<customAuthzClass value="org.some.custom.authz"/>
...
</securityConfig>2.1.6 Other Configuration
Some other security properties that can be configured as a part of the container or service descriptor are described below:
<context-lifetime value="lifetime in seconds"/>This sets the lifetime of the context that is created at the server end; the value is set in seconds.
If this option is not specified, the default value is the lifetime of the credential.
Relevant for all operations requiring GSI Secure Conversation authentication.
<reject-limited-proxy value="true"/>This requires that the credential presented by the client is not a limited proxy.
Relevant for all operations requiring GSI Secure Conversation or GSI Secure Message authentication.
Example:
<securityConfig xmlns="http://www.globus.org">
<method name="ogsi:findServiceData" xmlns:ogsi="http://www.gridforum.org/namespaces/2003/03/OGSI">
<run-as>
<caller-identity/>
</run-as>
</method>
<method name="ogsi:destroy" xmlns:ogsi="http://www.gridforum.org/namespaces/2003/03/OGSI">
<run-as>
<system-identity/>
</run-as>
</method>
<!-- default run-as for any other method -->
<run-as>
<service-identity/>
</run-as>
<context-lifetime value="100"/>
<reject-limited-proxy value="true"/>
</securityConfig>
In the above example, if the service is accessed using a limited proxy, an error is reported.
Also, the contexts created at the server end are set to have a lifetime of 100 seconds.
3.2 Programmatic altering of security descriptor
The security descriptor (container, security and resource) can be created and altered programmatically (as opposed to writing a security descriptor file.) For the service and container descriptor, we recommend writing a security descriptor file so that the security properties are initialized at start up.
Container Security Descriptor This is represented by
org.globus.wsrf.impl.security.descriptor.ContainerSecurityDescriptor.If a container security descriptor file is configured as described in Section 2, then an object is created and stored. To alter the values, use the API provided in
org.globus.wsrf.impl.security.descriptor.ContainerSecurityConfig.Service Security Descriptor This is represented by
org.globus.wsrf.impl.security.descriptor.ServiceSecurityDescriptor.If a service security descriptor file is configured as described in Section 3, then an object is created and stored. To alter the values, use the API provided in
org.globus.wsrf.impl.security.descriptor.ServiceSecurityConfig.Resource Security Descriptor This is represented by
org.globus.wsrf.impl.security.descriptor.ResourceSecurityDescriptor.To initialize the descriptor, i.e. load credentials and gridmap, use the API in
org.globus.wsrf.impl.security.descriptor.ResourceSecurityDescriptor. Refer to the description of resource security descriptor in Section 4.1 for more details.
3. Secure Resources
Resource level security can be set, which overrides any service or container level security.
To make a resource secure, it needs to implement org.globus.wsrf.impl.security.SecureResource.
This interface has a method that returns an instance of org.globus.wsrf.impl.security.descriptor.ResourceSecurityDescriptor.
If null is returned, it is assumed that no security is set on
the resource.
3.1 Resource Security Descriptor
The resource security descriptor is identical to the service security descriptor and contains API to set and get all properties that are described in Section 3.1. A descriptor file can also be used to create this object. The file needs to be written as described in Section 2.1.
Examples:
The following code snippet creates a resource descriptor object directly:
ResourceSecurityDescriptor desc = new ResourceSecurityDescriptor();
desc.setRejectLimitedProxy("true");The following code snippet creates a resource descriptor object from a file:
ResourceSecurityConfig config = new ResourceSecurityConfig("resDescFileName");There are two attributes of the security descriptor, credentials and gridmap, that can be specified as objects (
config.init();
ResourceSecurityDescriptor desc = config.getSecurityDescriptor();javax.security.auth.Subjectororg.globus.security.gridmap.GridMap) or path to credentials and gridmap. Similarly, either the custom authorization object or name of the custom authorization class can be specified. In the latter case, these need to be loaded from file; you can use the provided helper APIorg.globus.wsrf.impl.security.descriptor.ResourceSecurityConfigto do the same. The credentials, gridmap and custom authorization class are loaded if the propertyinitializedin the descriptor is set tofalse.For example, the code snippet below is a descriptor that has a gridmap file and specifies a custom authorization class name. When
config.init()is called, gridmap is loaded and an instance of the custom authorization class is created. Both are stored as a part of the security descriptor object itself.:ResourceSecurityDescriptor desc = new ResourceSecurityDescriptor();
desc.setGridMapFile("foo/bar/gridmap");
desc.setCustomAuthzClassName("org.globus.some.customAuthz");
ResourceSecurityConfig config = new ResourceSecurityConfig(desc);
config.init();If the descriptor property changes, force a reload by setting
setInitializedtofalse:desc.setInitalized(true);
desc.setGridMapFile("foo/bar/newGridMap");
config.init();GridMap and Subject object can also be set directly, i.e. without configuring files to be read:
desc.setInitalized(false);
GridMap map = new GridMap();
map.put("Some user DN", "userid");
desc.setGridMap(map);
3.2 Sample Secure Resource
In the examples below, a secure counter resource is created that sets security properties on itself:
Example 1:
- The counter resource implements the
SecureResourceinterface and hence has a method which returns a resource security descriptor.
- The security policy is defined so that when the value of the counter is greater than 100, the authorization scheme is altered to be gridmap. Prior to this change (i.e. for values less than 100), the authorization specified in the service (or container if not set on service) is used.
- The path to the gridmap file is specified as part of the descriptor; the ResourceSecurityConfig API loads it.
public class SecureCounter implements SecureResource {
...
ResourceSecurityDescriptor desc = null;
public void setValue(int value) {
if ((value > 100) && (this.desc == null)) {
this.desc = new ResourceSecurityDescriptor();
this.desc.setAuthz("gridmap");
this.desc.setGridMapFile("foo/bar/gridmap");
ResourceSecurityConfig config =
new ResourceSecurityConfig(this.desc);
config.init();
}
....
public ResourceSecurityDescriptor getSecurityDescriptor() {
return this.desc;
}
}Alternatively, the same policy can be expressed in a security descriptor file as shown below and that file can be used to create the resource security descriptor.
<securityConfig xmlns="http://www.globus.org">Example 2:
<gridmap value="foo/bar/gridmap"/>
<authz value="gridmap">
</securityConfig>
public class SecureCounter implements SecureResource {
...
ResourceSecurityDescriptor desc = null;
public void setValue(int value) {
if ((value > 100) && (this.desc == null)) {
ResourceSecurityConfig config =
new ResourceSecurityConfig("counter-security-config.xml");
config.init();
this.desc = config.getSecurityDescriptor();
}
....
public ResourceSecurityDescriptor getSecurityDescriptor() {
return this.desc;
}
}
4. Useful Security API
4.1 Setting service owner with caller's delegated credential
To associate credentials that a method invoker has delegated with a service instance, use:
import org.globus.wsrf.impl.security.SecurityManager;
...
public void serviceMethod(...) {
...
SecurityManager.getManager().setServiceOwnerFromContext(servicePath);
}
...In the above code,
servicePathis the service path specified in the deployment descriptor.The
SecurityManager.setServiceOwnerFromContext()operation requires a Subject object to be associated with the current thread of execution. That Subject object must also contain some private credentials.4.2 Getting caller's identity
To get the current caller's (client's) identity, use:
import org.globus.wsrf.impl.security.SecurityManager;
...
public void serviceMethod() {
String identity = SecurityManager.getManager().getCaller();
}
...4.3 Getting the current JAAS Subject
A JAAS Subject object contains authentication and authorization artifacts (such as principals), and public and private credentials (such as client's certificates), the delegated proxy credentials, etc.
GT4 allows a service operation to be invoked using one of the following:
- a null Subject
- the system/container Subject
- the service Subject
- the caller's Subject.
For more information on these JAAS Subjects, see Configuring Run-As Mode.
To get the current JAAS Subject, use:
import javax.security.auth.Subject;
import org.globus.gsi.jaas.JaasSubject;
...
public void serviceMethod() {
Subject subject = JaasSubject.getCurrentSubject();
}
...
The current Subject depends on the run-as policy specified in the security descriptor (again, see Configuring run-as mode). If no security descriptor is set for the service, the current Subject will be null.
4.4 Performing work as a particular JAAS Subject
A piece of code can also be executed with a particular JAAS Subject object. For example, to execute a piece of code with a given Subject object do the following:
import javax.security.auth.Subject;
import java.security.PrivilegedAction;
import org.globus.gsi.jaas.JaasSubject;
...
public void method() {
// create a new subject or obtain it from somewhere
Subject subject = ...;
JaasSubject.doAs(subject, new PrivilegedAction() {
public Object run() {
// do work here
return null;
}
});
}
...
5. Other Features
5.1 Replay Attack Prevention
If GSI Secure Message authentication is used, a replay attack filter can be configured on the server side. If activated, the filter can be configured with a time window, and only non-duplicate messages received within the window are accepted. The message received is expected to have a timestamp header as part of the security headers.
To facilitate this, relevant message details are persisted at the server end and a sweeper task is run periodically to delete expired messages.
The following parameters may be used to configure this feature:
- By default, a timestamp header is required as a part of any request using GSI Secure Message authentication.
This requirement can be disabled by setting the propertyreplayAttackFiltertofalse. This can be set either in the container or security descriptor (the latter overrides the former):<securityConfig xmlns="http://www.globus.org">
...
<replay-attack-filter value="false"/>
...
</securityConfig>- By default, a time window of 5 minutes is used for the replay attack filter.
This window value can be set in minutes using the elementreplayAttackWindowin either the container security descriptor or the service security descriptor (the latter overrides the former.) If the value set is not an integer or cannot be parsed for any reason, the default value of 5 minutes is used. The following example sets the window to 10 minutes:<securityConfig xmlns="http://www.globus.org">
...
<replay-attack-window value="10"/>
...
</securityConfig>
5.2 Writing a custom service authorization mechanism
The authorization handler can be configured to call out to a custom authorization class. The class must implement the interface
org.globus.wsrf.impl.security.authorization.ServiceAuthorization.If the authorization fails, then a
org.globus.wsrf.impl.security.authorization.AuthorizationExceptionshould be thrown.Example:
public class FooAuthorization implements ServiceAuthorization {
public void authorize(Subject peerSubject, ServiceProperties service, MessageContext context) throws AuthorizationException { // Evaluate and throw exception if not authorized. } }
6. Container-only Security Configuration
Other than the security properties that have been described in Security Descriptor, two more properties are exclusive to the container security descriptor.
- As a part of the support for Replay Attack Prevention,
a sweeper task is used to delete expired message values. This is run every
7 minutes by default. This interval can be set in milliseconds in the container
security descriptor as shown below:
<securityConfig xmlns="http://www.globus.org">
...
<replay-attack-interval value="10000"/>
...
</securityConfig> - When GSI Secure Conversation is used, a security context is established.
A sweeper task is run every 10 minutes to delete all expired contexts. This
interval can be set in milliseconds in the container security descriptor
as shown below:
<securityConfig xmlns="http://www.globus.org">
...
<replay-attack-interval value="10000"/>
...
</securityConfig>
8. Secure Notifications
Notification security is driven by the client. The security configuration on a subscribe call is used on the notify operation too. For example, if secure conversation with integrity is used on the subscribe operation, the notify is alsot secured similarly. Hence there is no change needed at the notification source for security.
For example, if notifications need to be secured with GSI Secure Message integrity, then the subscribe operation needs to be secured with the same, as shown below:
For example:
// Create endpoint reference
EndpointReferenceType endpoint = new EndpointReferenceType();
// Set address of service
String counterAddr =
"http://localhost:8080/wsrf/services/CounterService";
// Get handle to port
CounterPortType port = locator.getCounterPortTypePort(endpoint);
// enable GSI Secure Message message level security
((Stub)port)._setProperty(Constants.GSI_SEC_MSG,
Constants.SIGNATURE);
// set client authorization to none
((Stub)port)._setProperty(Constants.AUTHORIZATION,
SelfAuthorization.getInstance());
_Subscribe request = new _Subscribe();
// Construct request
...
...
port.subscribe();
Notes:
- Please refer to Client-side Security Document for details on setting security on the client side.
- The credentials used for securing the notification depends on credentials assocaited with the thread that spawns off the notification. The credentials associated with the thread is determined by the Run-as configuration.
The notification consumer can be configured to ensure that the notifications that are sent are secure by setting the required policy as a Resource Security Descriptor. Section 3.1 describes creating a resource descriptor and the example below shows creating a notification consumer that uses it.
Example:
ResourceSecurityDescriptor resDesc =
new ResourceSecurityDescriptor();
resDesc.setAuthz("self");
Vector authMethod = new Vector();
authMethod.add(GSISecureConvAuthMethod.BOTH);
resDesc.setAuthMethods(authMethod, true);
consumerEPR =
consumer.createNotificationConsumer(
new CounterClient(),
resDesc);This sample enforces that the notification received must be secured by GSI Secure Conversation (either privacy or integrity) and notifications are sent using the same identity as the client.
8. Limitations
8.1 Persistent Services Activation Run-As Identity
The activation of persistent services is not executed under any run-as identity. Wrong credentials might be used if the service is making an outbound connection during the activation. JAAS API might be used to set the right identity for the outbound connection.
8.2 Security Descriptor Requires Credentials
The presence of a security descriptor for a specific service triggers credential acquisition. This causes the service to require credentials, even if the security descriptor only specifies the
<none/>authentication method.As a workaround, we recommend that you remove the security descriptor. Secure invocation on a service without a security descriptor will still work (given that the service has credentials available.)
9. Errors
9.1 '[SEC05] Invocation subject not set'
The service method is calling
SecurityManager.setOwnerFromContext()but the run-as identity of the method is not set.The service is probably missing a security deployment descriptor.
9.2 '[SEC06] Invocation subject does not contain private credentials'
The service method is calling
SecurityManager.setOwnerFromContext()but the run-as identity of the method does not contain private credentials.If the method is run under the
callers-identity, make sure the client calling the service uses GSI Secure Conversation and enables delegation for the call.