Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.
Comment: Migrated to Confluence 5.3

Agreed API

  • @Secured
  • @SecurityBindingType
  • AccessDecisionVoter
  • SecurityStrategy

Agreed API and SPI of Part 1

commit: 1a2c7ffd0d0a1ad3dea34515a54958f0a6ce2932

API

Identity

Session scoped result of the authentication process.

Code Block

public interface Identity extends Serializable
{
    public enum AuthenticationResult
    {
        SUCCESS, FAILED
    }

    AuthenticationResult login();

    void logout();

    boolean isLoggedIn();

    User getUser();
}

User

Depending on further use-cases it can be refactored to an interface

The id is an unique identifier for an user. It isn't defined if it is an internal identifier or an identifier known by the user (like the user-name).
If users login e.g. via their e-mail address, it's possible to lookup an internal id in a custom implementation of LoginCredential or a bean which is in between (and LoginCredential doesn't get called directly in the 2nd case).

Code Block

@Typed()
public class User implements Serializable
{
    private static final long serialVersionUID = -2234530384311026364L;

    private final String id;

    public User(String id)
    {
        this.id = id;
    }

    public String getId()
    {
        return id;
    }
}

Credential

Credential is a holder for the "secret key" like a password.

Code Block

public interface Credential<T>
{
    T getValue();
}

LoginCredential (former Credentials)

Request scoped holder for the authentication process.

TODO we need a better name for it

  • LoginCredentialState
  • LoginCredentialHolder
  • LoginCredentialProvider
Code Block

public interface LoginCredential
{
    String getUserId();

    void setUserId(String userId);

    Credential getCredential();

    void setCredential(Credential credential);

    void invalidate();
}

Events

  • LoggedInEvent
  • LoginFailedEvent
  • AlreadyLoggedInEvent
  • PreLoggedOutEvent
  • PostLoggedOutEvent
  • PreAuthenticateEvent
  • PostAuthenticateEvent

SPI

AuthenticatorSelector

Request scoped bean used to find the current Authenticator for the authentication process - e.g. to provide different login-types used by the same client (e.g. a component in an UI).

TODO discuss default (internal) Authenticator if there is no custom implementation.

Code Block

public interface AuthenticatorSelector
{
    Class<? extends Authenticator> getAuthenticatorClass();

    void setAuthenticatorClass(Class<? extends Authenticator> authenticatorClass);

    String getAuthenticatorName();

    void setAuthenticatorName(String authenticatorName);

    Authenticator getSelectedAuthenticator();
}

Authenticator

Called by Identity and performs the final authentication based on the information in LoginCredential .

Code Block

public interface Authenticator
{
    public enum AuthenticationStatus
    {
        SUCCESS, FAILURE, DEFERRED
    }

    void authenticate();

    void postAuthenticate();

    AuthenticationStatus getStatus();

    User getUser();
}
Code Block

public abstract class BaseAuthenticator implements Authenticator
{
    private AuthenticationStatus status;

    public AuthenticationStatus getStatus()
    {
        return status;
    }

    protected void setStatus(AuthenticationStatus status)
    {
        this.status = status;
    }

    public void postAuthenticate()
    {
        // No-op, override if any post-authentication processing is required.
    }
}

Usage

Simple Login/Logout by Example (Java-SE)

Code Block

@ApplicationScoped
public class LoginBean
{
    @Inject
    private LoginCredential loginCredential;

    @Inject
    private Identity identity;

    public boolean login(String userName, final String password)
    {
        this.loginCredential.setUserId(userName);
        this.loginCredential.setCredential(new Credential<String>() {
            @Override
            public String getValue()
            {
                return password;
            }
        });

        this.identity.login();
        return this.identity.isLoggedIn();
    }

    public boolean logout()
    {
        this.identity.logout();
        return !this.identity.isLoggedIn();
    }
}

public class CustomBean
{
    @Inject
    private Identity identity;

    @Inject
    private LoginBean loginBean;

    public void execute()
    {
        if(this.loginBean.login("spike", "apache"))
        {
            User user = this.identity.getUser();
            //...
        }
        else
        {
            //...
        }
    }
}

Under discussion

API/SPI

Packages

  • */authentication
  • */authentication/events
  • */authorization
  • */authorization/annotation
  • */credential or */authentication/credential

Part 1

Feature

Comments

Objections

Discussion finished

Login via Username/Password

 

 

(plus)

Logout

 

 

(plus)

Authentication API and SPI

Credentials vs Credential (one of it needs a better name)

 

(plus)

Basic User/Identity API

 

 

(plus)

Duration of a valid authentication

ExpirationEvaluator SPI

 

 

Part 2

Feature

Comments

Objections

Discussion finished

Object level permission

 

 

 

Grant or revoke permissions

 

 

 

Basic Roles and groups API

optional type-safe (-> static) groups (and roles)

 

 

@SecurityMethodBinding

 

 

 

Super-users

 

 

 

User/Identity management

 

 

 

Password-Hash-Service

 

 

 

Group management

optional support for typ-safe groups/group-types

 

 

Part 3

Feature

Comments

Objections

Discussion finished

Support for deputies (see Impersonalization)

 

 

 

Privileges concept

 

 

 

UI SPI (Component based authorization)

add optional type-safe authorization; integration with JSF

 

 

Permissions of resources

Merge with CODI view-configs,...

 

 

Persistence SPI

integration with JPA

 

 

Identity Store SPI

 

 

 

Query API

 

 

 

Application roles

 

 

 

Part 4

Feature

Comments

Objections

Discussion finished

Support of alternative authentication concepts

Extend the Authentication SPI

 

 

Integration with authentication concepts of (application-) servers

Extend the Authentication SPI

 

 

Personalization

 

 

 

Alternatives for roles/groups

 

 

 

Permission for external applications

 

 

 

Use-cases

Authentication

Scenario

...

Example JSF code:

Code Block
xml
xml
 
Username: <h:inputText value="#{credentials.username}"/>
Password: <h:inputSecret id="password" value="#{credentials.password}"/>
<h:commandButton value="LOGIN" action="#{identity.login}"/>

...

Code Block
public class SimpleAuthenticator extends BaseAuthenticator implements Authenticator {
    @Inject Credentials credentials;

    @Override
    public void authenticate() {
        if ("demo".equals(credentials.getUsername()) &&
                credentials.getCredential() instanceof PasswordCredential &&
                "demo".equals(((PasswordCredential) credentials.getCredential()).getValue())) {
            setStatus(AuthenticationStatus.SUCCESS);
            setUser(new SimpleUser("demo"));            
        } else {         setUser(new SimpleUser("demo"));
        } else {
            setStatus(AuthenticationStatus.FAILURE);            
        }
    }
}

Scenario

It should be possible to provide an optional password service to create a password-hash based on the given password which will be stored instead of the real password.
Maybe there should be different default implementations (provided via qualifiers).

Scenario

The developer needs to authenticate application users stored inside corporate LDAP server.

Scenario

The developer must be able to easily support alternative authentication providers, such as those supporting services such as OpenID or token based authentication. Those can be more complex then just “username/password” scenario and require redirects to or communication with specific external ISP (Identity Service Provider)

...

Well thought API and SPI that doesn’t limit integration with those.
For some of those technologies where authentication is token based identity model needs to be capable of persisting needed information - token and reference to specific identity provider.
Ability to implement own authenticator that have access to IDM and Securtiy/Permissions API in it.
Provide automatic mapping between attributes returned by the Identity provider, and attributes stored in the local Identity store.
Allow authentication from alternative view technologies, (i.e. AJAX)

Scenario

The user must be able to authenticate automatically using a “Remember Me” feature, based on a unique cookie value stored by the user’s browser. For authentication performed in this manner, it must be also possible for the developer to configure a validation policy, which determines whether the user is required to provide their actual credentials for critical application operations such as changing passwords or e-mail address, placing orders, etc.

...

  • Validated for this request only
  • Validated for X minutes
  • Validated until end of session

Scenario

The developer must be able to easily integrate with AS security layer (JAAS/JAAC). Ideally by plugging DeltaSpike security into LoginModule stack.

Impersonalization

Scenario

Administrator needs to verify assigned access, applied changes or exposed resources for specific user. He authenticates “as a user” or access application imitating his identity - without knowing his password.

...

  • Facebook, see your profile as user 'bob'
  • Mary is away from the office and someone needs to execute something on her behalf

Authorization

Scenario

The developer must be able to control which elements of the user interface are displayed to the user based on the user's privilege level

...

Code Block
xml
xml
<div class="menu">
  <h:commandLink value="Admin functions" rendered="#{identity.hasRole('admin', 'APPLICATION')}" action="..."/>
</div>

Scenario

The developer must be able to control which elements of the user interface are displayed to the user based on their assigned permissions

...

Code Block
xml
xml
<table class="customers">
  <ui:repeat value="#{customerSearch.customers}" var="#{customer}">
    <tr>
      <td>#{customer.firstName}</td>
      <td>#{customer.lastName}</td>
      <td><h:commandButton value="Edit" rendered="#{identity.hasPermission(customer, 'EDIT')}" action="..."/>
    </tr>
  </ui:repeat>
</table>

Scenario

Sometimes developer may not have available instance of resource, which he wants to protect. It may be useful to ask for permission without need to obtain object from DB. It might be useful to have method: identity.hasPermission(String resourceType, String resourceId, String permission) in addition to current identity.hasPermission(Object resource, String permission)

...

Code Block
xml
xml
     <h:commandButton value="Edit page" rendered="#{identity.hasPermission('PAGE', 'AcmePage', 'EDIT')}" action="..."/>

Scenario

The developer must be able to restrict method access based on the user's privilege level.
Example:

(Already addressed with typesafe security annotations, e.g. @SecurityBindingType)

Scenario

The framework must provide a system for resolving object permissions, and the developer must have access to an SPI for easily providing their own custom permission resolver logic.

Scenario

The user (with the necessary privileges) must be able assign permissions to individual objects within the application’s business domain (i.e. ACL style permissions) and have these permissions persisted. These permissions should:

  • Be assignable to either the individual user, a group, or a role
  • Be stored using an identifier that is unique for the object that the permission is being granted for
  • Have configurable identifier policies, i.e. Entity beans will use an identifier based on the primary key value
  • Have a configurable permission store, i.e. it must be possible to store permissions in a database using JPA, etc.

Scenario

Further to the previous requirement, there must be an API for managing persistent permissions. Operations performed by the user on this API (such as granting or revoking permissions to/from other users) may be subjected to an additional security check.

Scenario

The developer needs to perform authorization checks based on information stored in corporate LDAP server or dedicated database. This external store contains information about all company employees and maps hierarchy including groups present in the organization with information about their members.

...

  • Restrict access to employees: identityManager.getUser(userName).hasRole(“member”, “/organization/employees”);
  • Restrict access to publishing content only to marketing
  • identityManager.hasRole(“member”,“john”,”/organization/departments/marketing”);
  • Restrict adding new members to a group only for its administrator
  • identityManager.hasRole(“administrator”, “john”, “/some/specific/group”);

Scenario

The developer needs to control access to application resources based on structure of groups and user roles

Scenario

Web application has a number of resources that needs to be secured with more fine grained security model. Invoking operations on a given resource needs to be restricted with a given permission. User can inherit set of permissions to the given resource from group to which he belongs or from role he posses.

...

Requirements:

Permissions model

Scenario

Application has a structure of resources. Permissions assigned to user for a given resource in the tree are inherited by other resources. User is able to edit all sub resources based on permissions assigned to parent resource.

...

  • Application has structure of pages.
  • User assigned to manage specific page should also be able to manage all sub pages.
  • Permissions are inherited.

Scenario

Application persists a structure of groups and users that have roles in those groups. Application developer needs to have some permissions related to one group be inherited by their sub groups.

...

  • Group “/organization” has assigned READ permission associated with “Corporate news” page
  • Group “/organization/it_dept” has assigned READ and CREATE permission associated with “IT Security Event Logs” page in the application.
  • All users with role in “/organizaiton/it_dept” will be able to read “Corporate news” page because READ permission will be inherited from “/organization” group.

Scenario

The developer needs to define several types of contexts in which user is connected with a given group to enable flexible authorization of different types of performed operations

...

Note that the @Project annotation is not a CDI bean Qualifier / Stereotype annotation, it is a method parameter security binding annotation that tells Seam Security to use the value of the Project passed to the method call in the security binding check itself.

Scenario

The developer needs to define single user or group that will serve as super users (aka root users. Those will have any available permissions.

...

  • identity.isRootUser()
  • identityManager.getRootUsers();

Scenario

Application needs to authorize access based on inherited group membership.

...

Example: You can configure that info about climbing trips will be available for “/communities/hiking*” but permission is denied for members for “/communites/hiking/juniors”. In this case, groups “/commuinites/hiking”, “/communities/hiking/instructors”, “/communities/hiking/seniors” will have permission. Members of group “/communities/hiking/juniors” won’t hav permission.

Scenario

The developer may want to have permissions based on other criterias than only roles/groups. Some of these requirements can be handled by XACML integration mentioned below.

  • I want page "hobby" to be accessible for employees only after 6pm, to enforce that my employees won't go to hobby page during their working time.
  • I want forum portlet with "Retiree forum" to be accessible only for users older than 60 years. Only exceptions can be "/platform/administrators" group, whose members can access page everytime regardless of their age.

Scenario

The developer needs to integrate application with more advanced security resolution mechanisms.

...

Well thought API/SPI that doesn’t limit such integration.

Scenario

The developer needs to expose part of application features to be accessible by external services and authorize their access.

Delegated Administration

Scenario

Web application has a number of user groups or resources that needs to be managed. It is desired that management permission to only part of those are delegated to specific user

...

All use cases with strong focus around concepts and operations on User, Group and Role

Scenario

Application needs to expose basic user management capabilities. To register new user, edit profile and remove old users. Basic provisioning and management API for user, group and role.

...

Code Block
User johnUser = identityManager.createUser(“john);
johnUser.setEmail(“john@acme.com”);
johnUser.enable();
johnUser.addRole(“member”, “/employees”);
johnUser.setAttribute(“manager”, “Max Kowalski”);

Scenario

Application needs to enable groups management capabilities. Administrators must be able to map organization structure in the application to be able to set proper security restrictions

...

Code Block
Group parisOffice = identityManager.createGroup(“paris”, “/global/offices/emea/”);
parisOffice.addRole(“manager”, “ John Doe”);
parisOffice.setAttribute(“displayName”, “Paris Office”);
parisOffice.setAttribute(“address, “......”);

Scenario

Application needs to enable group based security that maps relationships from real organization structure. Therefore users need to be associated with specific groups in organization hierarchy and have defined roles in context of those groups

...

Code Block
Group itsec = identityManager.createGroup(“itsec”, “/organization/engineering/security”);
itsec.addRole(“manager”, “johnDoe”);
Group hr = identityManager.createGroup(“hr”, “/organization”);
hr.addRole(“supervisor”, “aliceDoe”);
hr.addRole(“headhunter”, “chrisDoe”);
aliceDoe.hasRole(“headhunter”);
List<User> headHunters = identityManager.createUserQuery().setRole(“headhunter”).sort(true).setRange(Range.of(0,50).execute(); 

Scenario

Application needs to expose capabilities to associate authenticated user with specific roles in application context.

...

Code Block
identity.addApplicationRole(“SuperUser”);
identity.addApplicationRole(“Authenticated”);

Scenario

The developer needs to query user, groups and roles in a way that will not affect performance. He needs to sync into database 500k user entries from corporate LDAP server and quite big group structure. Methods like identityManager.getAllUsers() will be performance bottlenecs. The developer needs to obtain pagainated and sorted results.

...

Code Block
identityManager.createGroupQuery().setRelatedUser(“john”).setParentGroup(“/offices”).sort(true).setRange(Range.of(0,10)).execute();

Scenario

The developer needs to query user by unique attribute (email) and group membership when “new user registration” form is submitted in the application.

...

Code Block
identityManager.createUserQuery().setRelatedGroup(“/employees”).setAttributeFilter(“personal.email”, values).setRange(Range.of(0.100));

Scenario

The developer needs to persist user, group and role information in database. JPA implementation is his dream.

Scenario

The developer want to give freedom to plug different type of identityStore into his application in the future. Not all identity store expose equal operations for pagination, sorting or querying by attributes. He needs to design his GUI so it can query underlying IdentityStore if specific operations are supported.

...

Code Block
identityManager.getSupportedFeatures().isUserSortSupported();
identityManager.getSupportedFeatures().isUserQueryPaginationSupported();

Events

Scenario

Application developer needs to add specific hooks for common IDM or Security operations

...

This is not fully related to security but it is tightly coupled with identity model that is already in place

Scenario

The developer needs to let application users set their own locale. He also needs to set default ones per group of users. For case that user is member of more groups, we need to specify which group will have priority for determining the defaultLocale (or other attribute) for user. Some groups can be ignored.
Examples:

Group “/application_users” have attribute “defalutLocale”. All users with role “member” in this group inherit this attribute. Each user can override this value
User is member of “/application_users” and “/partners” . Group “/application_users” has default locale “fr” and group “/partners” has default locale “en”. We assume that “/application_users” has bigger priority so defaultLocale of user will be “fr”.

Scenario

The developer needs to let application users set their own skin in their application. He also needs to set default skins per group of users.
Examples:

Groups “/vendors”, “/partners” and “/employees” have different value of attribute “defaultSkin”. Their members inherit this attribute value.

LDAP or External Identity Store Integration

Integrating external identity store is a common scenario for application developers. Most common case is corporate LDAP or MSAD hosting users in Windows Domain. However other custom solutions like Web Service or REST based services for IDM are often spotted in organizations.

There are 3 ways such internal store can be integrated. At least “Direct Integration” and “Synchronization” scenarios need to be addressed

Scenario - Direct Integration

In such case application developer replaces default JPA based identity store implementation with custom one.

...

Other limitation is typically less flexible query mechanism. For example in LDAP you cannot easily perform efficient query with multiple conditions that would be sorted and paginated. With flexible Query API and big number of identity entries in the store it is a rising issue. Implementing rich IDM API/SPI can easily create performance bottlenecks

Scenario - Identity Store Routing

In this scenario application developer implements routing to invoke methods on several identity stores and merge results. In simplest case part of user attributes (limited by LDAP schema) and information about user roles are kept in JPA implementation. Users and groups can be created in external store based on routing configuration.

...

Still some operations like authentication are performed directly on external store. Reason is that modern authentication systems won’t expose password but just validatePassword type of operation.

Examples:

  • During user authentication LDAP is queried if user profile or group assignment was updated and this information is synced into default identity store.
  • During identity.setAttribute() operation external store is also updated.
  • During any “write” operation external store is updated with applied change.
  • Scheduler is triggering synchronizing operation.
  • There is manual synchronization hook that can be invoked to trigger synchronization when administrator update information in external store.