Authentication and authorization

IBM® WebSphere® sMash authentication is based on the Java™ Authentication and Authorization Service (JAAS), which allows various types of login modules to be added to the programming model without changing the authentication model.

Security rules

WebSphere sMash security leverages the user service that defines the users and groups referenced in the security rules. Security rules define protected resources. Resources that are not covered by any security rule are not protected.

When security is enabled, the default conditions protect all resources associated with a particular application. The following example shows how to protect all resources, for a given application, to users that are members of the CUSTOMERS group:

## Required by default for security
## See note below for further details
/config/security/secretKey="XXXXXXXXXXXXXXXXXXXX"

@include "security/enableSecurity.config"{
	# default condition is to enable security
	# for all resources regardless of request method
	"conditions" : "/request/path =~ /(.*)?"
}
@include "security/basicAuthentication.config"{
	# default condition is to require authentication
	# for all resources regardless of request method
	# "conditions" : "/request/path =~ /(.*)?",
	# enable CSRF protection defaults to true
	# "csrfProtect" : true
}
@include "security/authorization.config"{
	# default condition is to require authorization
	# for all resources regardless of request method
	# "conditions" : "/request/path =~ /(.*)?",
	# default is an empty list of users, groups and roles
	# "users" : [],
	# "groups" : [],
	# "roles" : []
	"groups" : ["CUSTOMERS"]
}

Though the default is to protect all resources when the application includes the security stanzas in the previous example, there are situations in which applications must specify certain conditions under which the security constraints are required. For these instances, the configuration options detailed in the following sections are provided for each of the include templates.

The default security token is SimpleToken. Simple token support requires the specification of a secret key that is leveraged to encrypt the content of the simple token when it is sent to the client. Refer to the article Secret key encryption for more details on generating a secret key.

Enabling security

Enabling security for an application requires inclusion of the enableSecurity.config template. This template is used to enable security for the application, regardless of the authentication type. Security for the application can be disabled by simply commenting out the enableSecurity configuration stanza while leaving all of the security rules in place for the application.

The enableSecurity.config stanza is demonstrated in the following example.

@include "security/enableSecurity.config"

Enabling security configuration options

The template enableSecurity.config is provided as a convenience template for enabling security for the application. By default, security is disabled for all WebSphere sMash applications. When including this configuration file without any parameters, as shown in the previous example, the secure event handler is registered and fired for all HTTP requests.

conditions
An optional parameter used to specify conditions under which the secure event is fired. The default condition is "/request/path =~ /(.*)?". This represents all URIs associated with the application for all HTTP methods.

The suggested method for enabling security is to not specify the conditions clause for the enableSecurity.config template. If there is a requirement to specify a conditions clause, ensure that the login page (for example, for authentication types such as Form-based authentication and OpenID authentication) URIs are covered by the pattern specified in the conditions clause.

Types of authentication

Authentication is responsible for obtaining and validating user credentials and populating the /request/subject with the appropriate user information. WebSphere sMash provides implementations of the following types of authentication:

Basic authentication
Basic authentication is defined in RFC 2617.
Form-based authentication
The full page form login that leverages external redirect.
Single sign-on authentication
The URL-based login that leverages HTTP request attributes, including support for Security tokens such as LTPA.
OpenID authentication
Provides OpenID consumer based authentication for third party authentication with an OpenID provider.
Programmatic login authentication
Provides an API-based authentication model.

Basic authentication

Basic authentication is defined in RFC 2617.

To enable basic authentication, specify the following configuration stanzas:

  • The first stanza is responsible for the rules associated with the resource that is being secured. This rule protects all resources that match the URI pattern /customers(/.*)? and the request methods of PUT or POST with basic authentication as the following example shows:
    @include "security/basicAuthentication.config"{
       "conditions": "(/request/path =~ /customers(/.*)?)  && (/request/method =~ (PUT|POST)) "
    }
  • The second stanza is responsible for defining the access privileges for resources that are being secured. This rule permits the user myUser1 or a member of the groups CUSTOMERS to access all resources that match the URI pattern /customers(/.*)? and the request methods of PUT or POST.
    @include "security/authorization.config"{
       "conditions": "(/request/path =~ /customers(/.*)?)  && (/request/method =~ (PUT|POST)) ",
       "users" : ["myUser1"],
       "groups" : ["CUSTOMERS"]
    }

This set of configuration stanzas protects all of the resources that match the URI pattern /customers(/.*)? which are accessed with the HTTP method of PUT or POST with basic authentication. In this example, users must either be the user named myUser1 or a member of the CUSTOMERS group.

You can configure an optional realm to be used by basic authentication as shown in the following example:

/config/security/realm="Secure Area"

If no realm is set, the default realm is Secure Area.

Basic authentication security flow

When a request is received for a protected resource the following events take place:

  1. The incoming request is checked for a valid token.
  2. If no token is found, the incoming request is checked for user credentials and a login is attempted.
  3. If the login is unsuccessful, then the client is sent a 401 status header along with a request for credentials. If the login is successful, then a token is generated for subsequent requests and an authorization check is performed.
  4. If authorization is unsuccessful, then a 403 unauthorized status header is returned to the client. If authorization is successful, the protected resource is served.

Form-based authentication

To enable form-based authentication, you specify the following configuration stanzas.

  • The first stanza required is to enable security for the application. See the Enabling security section of this article for further details.
  • The second stanza is responsible for configuration associated with the form. The property for this configuration setting is formLoginPage, which specifies the location of the form login page, as shown in the following example.
    @include "security/formLoginURL.config"{
       "formLoginPage" : "/login/index.html"
    }
  • The third stanza is responsible for rules associated with the resource that is being secured. This rule protects all resources that match the URI pattern /formauth/customers(/.*)? with form-based authentication as the following example shows:
    @include "security/formAuthentication.config"{
       "conditions": "/request/path =~ /formauth/customers(/.*)?"
    }

    The third stanza is also responsible for defining the access privileges for resources that are being secured. This rule permits any authenticated user to access all resources that match the URI pattern/formauth/customers(/.*)? . As an authenticated user, you can access as the following example shows:

    @include "security/authorization.config"{
       "conditions": "/request/path =~ /formauth/customers(/.*)?"
       "groups" : ["ALL_AUTHENTICATED_USERS"]
    }

To use the logout function, you must configure the logout handler at a given location, as shown in the following example, and send the request for logout as a POST:

/config/handlers += [{
   "events" : "POST",
   "handler" : "zero.core.security.LogoutHandler.class",
   "conditions" : "/request/path == /logout"
}]

Creating a login form

To use form-based login, you must create a login form at the location specified by formLoginPage. The following list contains the requirements for this form:

  • The method must be POST.
  • The action must result in the request going to the login page, formLoginPage, when it is submitted. If you navigate to the login page as a result of directory indexing, such as requests to the root of the application without a resource explicitly listed, the action needs to be formLoginPage. For all other types of requests, the action can be left blank.
  • The username field must be named zeroUserName.
  • The password field must be named zeroPassword.

The following example is a sample form:

<html>
        <form method="POST" action="">
        <input type="text" name="zeroUserName">Username</input><BR>
        <input type="password" name="zeroPassword">Password<BR>
        
        <!-- optional hidden value used in requesting unprotected form login page scenario -->
        <--  <input type="hidden" name="postLoginTargetURI" value="secure/index.gt"> --> 
        
        <input type="submit" value="Submit"/>
        </form>
</html>

Form-based security flow

You can request a protected resource or an unprotected form login page.

Requesting a protected resource

When a request comes in for a protected resource, the following events occur:

  1. The incoming request is checked for a valid token.
    • If a token is not found, then a 302 is sent to the client to redirect it to the login page, as defined in the configuration file under the formLoginPage entry.
    • If a token is found, then the URI for the protected resource is added as a query parameter named postLoginTargetURI to the login page URL. The form posts back to itself with an empty action when it is submitted.
  2. A login is attempted with the incoming credentials.
    • If the login is unsuccessful, then the login page is returned again with a 200 status code.
    • If the login is successful, then a token is generated for subsequent requests, and a 302 status code is sent to the client to redirect it back to the original protected resource, which is stored in the postLoginTargetURI query parameter.
  3. The incoming request for the protected resource contains a valid token and an authorization check is performed.
    • If authorization is unsuccessful, then a 403 unauthorized status header is returned to the client.
    • If authorization is successful, then the protected resource is served.

Requesting an unprotected form login page

When a request comes in for the form login page, the following events occur:

  1. A login is attempted with the incoming credentials.
    • If the login is unsuccessful, then a login page is returned again with a 200 status code.
    • If the login is successful, then a token is generated for subsequent requests, and a 302 status code is sent to the client to redirect it back to the a protected resource, which is stored in the hidden postLoginTargetURI form field parameter.
  2. The incoming request for the protected resource contains a valid token and an authorization check is performed.
    • If authorization is unsuccessful, then a 403 unauthorized status header is returned to the client.
    • If authorization is successful, the protected resource is served.

If the FormBasedLoginHandler does not receive the parameter postLoginTargetURI, you are redirected to the context root of the application where you can define a default file resource to handle the request.

Single sign-on authentication

WebSphere sMash single sign-on is scoped to the domain of the WebSphere sMash application. To enable WebSphere sMash single sign-on based authentication, specify the following configuration stanzas.

  • The first stanza contains configuration information for the single sign-on. The property for this configuration setting, as shown in the following example, is ssoURL which specifies the location of single sign-on service.
    /config/security/realm="Secure Area"
    @include "security/ssoLoginURL.config"{
       "ssoURL":"/sso/login"
    }

    You can also configure an optional realm to be used by single sign-on. If no realm is set, the default realm is Secure Area.

  • The second stanza is responsible for rules associated with the resource that is being secured as shown in the following example.
    @include "security/ssoAuthentication.config"{
       "conditions": "/request/path =~ /ssoauth/customers(/.*)?"
    }

    This rule protects all resources that match the URI pattern /ssoauth/customers(/.*)? with single sign-on authentication.

  • The third stanza is responsible for rules associated with defining access privileges for the resource that is being secured. This rule permits any authenticated user that is part of the groups CUSTOMERS to access all resources that match the /ssoauth/customers(/.*)? URI pattern, as the following example shows:
    @include "security/authorization.config"{
       "conditions": "/request/path =~ /ssoauth/customers(/.*)?",
       "groups" : ["CUSTOMERS"]
    }

For information about single sign-on scoped at a domain level, see the Security Token Support article.

To use the logout function, configure the logout handler at a given location, as shown in the following example, and send the request for logout as a POST.

/config/handlers += [{
   "events" : "POST",
   "handler" : "zero.core.security.LogoutHandler.class",
   "conditions" : "/request/path == /logout"
}]

Creating a login form

You can implement WebSphere sMash single sign-on in a variety of ways. Start with the preceding Creating a login form example and convert to a login widget. The main difference is the URL receiving the POST request must be the ssoURL. The following requirements must also be met:

  • The target URL must be the location specified in the ssoURL field in the zero.config file.
  • The username field must be named zeroUserName.
  • The password field must be named zeroPassword.

The following code sample is an example login form leveraging Dojo:

<form id="loginForm" action="/sso/login" >
        <input type="text" value="UserName" name="zeroUserName"/>
        <input type="password" name="zeroPassword" />
        <input type="button" value="login" onClick="loginUser(); return
false;"/>
</form>
<script type="text/javascript"> 
        function loginUser(){
                var form = dojo.byId('loginForm');
                var username = form['zeroUserName'].value;
                var password = form['zeroPassword'].value;
                var jsonString = dojo.toJson({zeroUserName: username,zeroPassword: password });
                var request = {
                        url: '/sso/login',
                        postData: jsonString,
                        sync: false,
                        handleAs: 'text',
                        contentType: 'text/json',
                        handle: function(response, ioArgs){
                                form.reset();
                        },
                        load: function (response, ioArgs){
                                // do something
                                return response;
                        },
                        error: function (data, ioArgs){
                                // do something
                                return data;
                        }
                        var deferred = dojo.rawXhrPost(request);
        }
</script>  

For scenarios in which using a JSON is not preferred, SSO also supports form URL encoded parameters. The names of the parameters, zeroUserName and zeroPassword, are the same. The target URL, ssoURL defined in the zero.config file, also remains the same as the login form example.

Single sign-on security flow

By default, WebSphere sMash single sign-on can be viewed in two types of requests. The first type of request is the login, and the second type is requests sent to protected resources that can occur multiple times.

Type 1 request

When a request is made to the single sign-on resource the following events occur:

  1. The incoming request is checked for a valid token.
  2. If no token is found, the incoming request is checked for user credentials and a login is attempted.
    • If the login is unsuccessful, then the client is sent a 401 status header, along with a request for credentials.
    • If the login is successful, then a token is generated for subsequent requests.

Type 2 request

When a request comes in for a protected resource, the following events occur:

  1. The incoming request is checked for a valid token.
    • If a token is not found, then the client is sent a 401 status header indicating that it is not authenticated. This requires the client to authenticate using the SSO authentication resource as described in the Type 1 request section.
    • If a token is found, then the incoming request for the protected resource contains a valid token and an authorization check is performed.
  2. If authorization is unsuccessful, a 403 unauthorized status header is returned to the client. If authorization is successful, the protected resource is served.

Programmatic login authentication

To enable programmatic login, configure the user registry for either LDAP or file based repositories. The default user registry is file-based and only requires the zero.users file. See the User service section for information about the various configuration options.

Programmatic login authentication code sample

The following sample leverages http request parameters to obtain the username and password values for the client.

/*login.groovy script*/
package programmatic;

import zero.core.security.LoginService;

String userName = zget("/request/params/userName");
String password =  zget("/request/params/password");
boolean success = LoginService.login(userName, password);

Programmatic login provides a flexible way to obtain userid and password information while still allowing access to the user registry provided by WebSphere sMash. When authentication is successful and the login returns true, you can then retrieve user information.

Programmatic login authentication security flow

When a request comes in for an unprotected resource, the following events occur:

  1. You call the LoginService.login function with username and password as arguments.
    • If the login is unsuccessful, then the API returns false indicating that you are not authenticated.
    • If the login is successful, then the token is generated, and your credentials are populated in the GlobalContext and are accessible by the application.

Programmatic logout code sample

The following sample uses the LoginService function to log off programmatically.

/*logout.groovy script*/
package programmatic;
import zero.core.security.LoginService;
boolean success = LoginService.logout();

After you successfully log off, your token is discarded and is considered not authenticated for the current request, or for subsequent requests, until you start the authentication process again.

Programmatic logout authentication security flow

When a request comes in for a protected resource, the following events occur:

  1. You call the LoginService.logout function with zero arguments.
    • If the logoff is unsuccessful, then the API returns false indicating you are not logged out.
    • If the logoff is successful, then the token is removed, and your credentials are removed from the GlobalContext and are not accessible by the application.

Authentication configuration options

The templates <authenticationType>authentication.config are provided as convenience templates for enabling authentication for the application. When including these configuration files without any parameters, the authentication specific authenticate event handlers are registered and fired for all HTTP requests.

Enabling authentication first requires the enablement of security. To enable security, include the enableSecurity.config template in the zero.config file of the application. This is necessary because the authenticate event is fired by the default secure event.

To change this default behavior, you can use the following parameters:

conditions
An optional parameter to specify conditions under which the authenticate event is fired. The default condition is "/request/path =~ /(.*)?". This represents all URIs associated with the application for all HTTP methods.
csrfProtect
An optional parameter to specify whether this protected resource is CSRF protected. The default is true. ( Advanced )

The previous configuration options pertain to the following authentication configuration templates:

  • basicAuthentication
  • formAuthentication
  • ssoAuthentication
  • openidAuthentication
  • taiAuthentication

Authorization configuration options

The authorization.config template is provided as a convenience template for declaring authorization rules for the application. When including this configuration file without any parameters, the authorize event handler is registered and fired for all HTTP requests.

Enabling authorization first requires the enablement of security. To enable security, include the enableSecurity.config template in the zero.config file of the application. This is necessary because the authorization event is fired by the default secure event. If the there are no authorization event handlers matching a given request, the security runtime will consider the user authorized to access the resource.

conditions
An optional parameter used to specify conditions under which the authorize event is fired. The default condition is "/request/path =~ /(.*)?". This represents all URIs associated with the application for all HTTP methods.
users
An optional list of users, separated by commas, that are allowed to access these resources.
groups
An optional list of groups, separated by commas, that are allowed to access these resources.
roles
An optional list of user roles, separated by commas, that are allowed to access these resources. ( Advanced )

Depending upon the requirements of an application, there may be a need to define an authorization policy without requiring authentication. For example, an application may need to restrict access to a defined set of resources that even authenticated users are not granted permission to. The following example shows how to configure an application to require authorization without defining an authentication rule.

# enable security for the application
@include "security/enableSecurity.config"

# require authorization for this set of resources
@include "security/authorization.config"{
  "conditions" : "/request/path =~ /foo(|/(|.*))"
}

In this example, there are no users, groups or roles associated with this authorization rule. Since there are no users, groups or roles defined, authorization will fail for this request.

Retrieving user information

After WebSphere sMash has verified the credentials, they are available in the request context as a Map at /request/subject. The Map contains the remote_user and groups keys, as shown in the following examples.

The following example shows the Map with the remote_user and groups keys in Java code:

// java snippet
String remoteUser = GlobalContext.zget(zero.core.context.GlobalContextURIs.Request.Subject.remoteUser);
java.util.List groupNames = GlobalContext.zget(Request.Subject.groups);

The following example shows the Map with the remote_user and groups keys in Groovy code:

// groovy snippet
RemoteUser: <%=request.subject.remoteUser[] %>
Groups:  <%=request.subject.groups[] %>

The following example shows the Map with the remote_user and groups keys in PHP code:

<?php
// php snippet
$remoteUser = zget("/request/subject/remoteUser");
$groups = zget("/request/subject/groups");
?>

This information is only available when accessing protected resources. If you want to use this information when accessing non-protected resources you can store it in the user's session.

Related articles

Version 1.1.30763