ONJava.com -- The Independent Source for Enterprise Java
oreilly.comSafari Books Online.Conferences.

advertisement

AddThis Social Bookmark Button

Java vs. .NET Security, Part 4
User Authentication and Authorization

by Denis Piliptchouk
02/25/2004

This is the fourth and final article in this series comparing Java and .NET security. It discusses implementations of user authentication and authorization on those platforms. Previous articles of this series covered configuration and code containment in Part 1, cryptography support and the mechanisms of communication protection in Part 2, and code protection and Code Access Security (CAS) in Part 3.

When authentication comes into play, the system should already have a strong foundation, defined by the features discussed in previous articles. Authentication adds to that bag an ability to determine whether the user is the person he claims to be. Results of the authentication process are usually passed on to the authorization step.

The issue of user authorization (a.k.a. role-based security) comes after solidifying the platform's base. At that point, in any more or less advanced system the administrator is left to be the judge, determining who is allowed to do what. This is traditionally done in two ways: using ACL to protect a particular resource (this is known as Discretionary Access Control, or DAC), or checking a user's group (or role) membership and allowing/denying him an operation based on the results of this check (a variation of Mandatory Access Control, or MAC).

User Authentication: General

The process of authentication starts right after identification by collecting caller credentials, confirming the identity claim, and securely communicating them to the server. Those credentials (possibly several types of them, so it's called multi-factor authentication) are matched against the registered account information and a positive or negative answer is returned regarding the claimed identity.

To do this work, application developers can either utilize standard platform facilities, as described below, or roll out some custom authentication solution (for instance, biometric readers), which is outside of the scope of this article. This article also does not cover RMI and remoting authentication, since their status was already discussed in Part 2.

Related Reading

Programming .NET Security
By Adam Freeman, Allen Jones

.NET includes a web solution for the server side: ASP.NET, which is coupled with IIS for processing HTTP requests. It is also possible to attach it to a different web server, if an appropriate server extension is supplied. The IIS extension is called aspnet_isapi.dll, and handles all requests directed to ASP.NET (the suffixes ASPX, ASMX, etc). ASP.NET itself, however, runs separately from IIS, in the aspnet_wp.exe process, so process isolation settings in IIS do not matter much. All managed code is executed in the worker process, and requests are forwarded there from the aspnet_isapi.dll extension through a named pipe.

Based on its configuration, IIS can either authenticate the requestor against a Windows account, using one of its standard methods (NTLM, Kerberos, Basic, Digest, Certificates) before forwarding the request, or forward the unauthenticated call to the ASP.NET handler. It is important to remember that security settings of IIS and ASP.NET are unrelated, although the latter uses IIS services for particular kinds of authentication.

ASP.NET handles authentication via so-called Authentication Modules, one per each authentication type that APS.NET supports, which reside in the System.Web.Security namespace. They all provide an OnAuthenticate event handler, which can be used to create a custom authentication/authorization schema by using different user account mapping and attaching new custom principals to the thread context.

The Java platform defines two solutions for user authentication to the servers: JAAS and servlets. Although EJB does not have its own authentication facilities, and its 2.1 specification does not require any particular authentication mechanism from vendors, it does mention the requirements for propagating the Principal object (see the Identities section), created in a server-specific manner.

Java servlets is the Java platform's HTTP-oriented server layer, which performs HTTP processing functions similar to those of the ASP.NET layer. Correspondingly, the servlet's security model is intended specifically to handle the requirements of web applications.

JAAS may be used to add authentication and authorization to any Java-based application (executable, bean, applet, etc). It defines an API-based, configurable generic authentication mechanism, independent of the underlying methods. The power of this approach lies in the clear separation of application and authentication code, allowing transparent replacement or alteration of authentication mechanisms.

User Authentication: Identities

In both systems, a principal and his identity (or identities) are established as a result of the authentication process, which serve to represent the user in the application during his further requests.

A user and his roles are represented in .NET via objects, implementing the IIdentity and IPrincipal interfaces, attached to the current thread context. IIdentity provides access to name and authentication type information, and IPrincipal provides access to the contained user identity (one-to-one relationship) and role membership information. .NET provides two sets of implementations of those interfaces -- WindowsPrincipal with WindowsIdentity, and GenericPrincipal with GenericIdentity. If the user does represent a Windows authorized account, he may use a WindowsIdentity, and this object represents a Windows security token, with role membership and authorization type derived from the Windows token. Generic versions of interfaces are used to implement any additional type of principal, unrelated to Windows accounts.

WindowsPrincipal principal = 
      (WindowsPrincipal)Thread.CurrentPrincipal;
WindowsIdentity identity = 
      (WindowsIdentity)principal.Identity;

There is no required relationship between the identities used by the CLR and the current Windows process token, because the CLR has a separate security context from that of Windows. In fact, the CLR thread might not have an associated identity at all (or, rather, an empty one), while Windows threads always have one. In order for the CLR thread to take on the Windows thread's WindowsIdentity (to synchronize, using .NET jargon), it has to be configured to use WindowsAuthenticationModule. Otherwise, CLR and process threads will have two different identities.

As opposed to .NET's hierarchy, Java uses the word Principal, and the corresponding interface, java.security.Principal, to represent a user's identity. This user object carries only username information in it, not roles or any additional attributes about the logged-on user. This design reflects the focus on Code Access Security prevailing in J2SE, since user-access checks were not initially the main point of concern for Java designers. As for the identity synchronization with the OS thread, the J2EE specifications merely state that for single sign-on capabilities, a compliant J2EE product must be able to relate those identities.

Clearly, having only a username is not sufficient for any kind of serious application, so JAAS augmented it with additional information. JAAS groups multiple Principal objects, representing the same user, into a single Subject, which also holds the user's credentials, such as password, certificate, or any kind of user-related information.

public final class Subject {
    public Set getPublicCredentials(); //not security-checked
    public Set getPrivateCredentials(); // security-checked
    public Set getPrincipals();
    ...
}

User credentials, obviously, have to be stored somewhere, for matching them later during the authentication process. Both platforms support multiple storage formats for user accounts: OS, disk-based files, database, and directory services. Necessary care must be taken to configure these storage areas properly, using file protection, secure hosts, communication encryption, etc.

ASP.NET applications have several options for storing user credentials:

  • Through IIS, it can use whatever storage options are configured there (Windows account database, Active Directory Service).

  • The Passport accounts directory.

  • For the simplest case of Forms mode, user credentials can be stored right in the application's configuration file. However, this approach has obvious maintenance drawbacks.

    <credentials passwordFormat="SHA1">
      <user name="User1" password="3784AAB557DC76789FFA">
      <user name="User2" password="23933DCA564EE">
    </credentials>

Neither Java nor J2EE specifications define any specific storage means for user accounts. The applications are capable of using directory services via the JNDI mechanism, as well as other custom or vendor-provided solutions. Additionally, most commercial J2EE application servers provide some kind of mapping between the underlying OS' accounts and J2EE users and groups.

When a user logs in, a new session is created on the server and associated with that user. Servers typically terminate user sessions after some period of inactivity, as configured or set in the code.

ASP.NET applications map user requests to the Session objects, with their timeouts (in minutes) determined by sessionState tags in the web.config application file or through a global setting in machine.config.

<sessionState timeout="20"/>

To track user sessions, Java servlet engines use the HttpSession object. The sessions can be managed automatically and/or manually, providing expiration time to prevent session hijacking. The servlet container determines the default timeout for servlets sessions, which can be retrieved by calling HttpSession.getMaxInactiveInterval, and changed by calling HttpSession.setMaxInactiveInterval. Specifying "-1" as the timeout interval means that the session never expires. An application can also override the default timeout by setting the desired value (in minutes) in its web.xml file:

<web-app>
  <session-config>
    <session-timeout>20</session-timeout>
  </session-config>
</web-app>

In EJB servers, Principals are associated with callers' requests in server-specific ways. J2EE specifications require that for all EJBs in a call chain within the same application the same identity must be returned for all calls to EJBContext.getCallerPrincipal, which should be the same identity as in HttpServletRequest.getUserPrincipal if that is not null. Whereas servlet specifications do allow returning a null Principal, EJB specifications explicitly state that a non-null object should be returned at any time, even for representing an unauthenticated user.

EJB specification does not dictate any programmatic ways of propagating principals in the case of calling multiple beans or even multiple servers. Some EJB servers implement a principal delegation mechanism akin to Java's doPrivileged privileged code execution. If desired, the application assemblers, via the deployment descriptor, may affect the choice of identities that execute their beans. There is <security-identity> element for that, which has two possible values:

  • <use-caller-identity>: To force using caller's identity on any method of the bean by propagating it from the caller.

  • <run-as>: To specify a particular role to run the bean.

    <security-identity>
      <run-as>
        <role-name>Administrator</role-name>
      </run-as>
    </security-identity>

Pages: 1, 2, 3, 4, 5

Next Pagearrow