Web Application Security

From NovaOrdis Knowledge Base
Jump to navigation Jump to search

External

Internal

Overview

Security of a web application is based on the concept of role. For more on roles, see https://home.feodorov.com:9443/wiki/Wiki.jsp?page=J2EESecurity. Role-based access is defined relative to URL patterns. Protected content is declared using the web.xml <security-constraint> element.

The example below represents a typical declarative security configuration. Assuming that the servlet is mapped to "/*" relative to the context root - which by default is the name of the servlet WAR ("test-servlet") or the value of the context-root element from application.xml - and we want to secure all content that is mappend under "test-secure" and "test/secure/2" sub-paths, the configuration is:

<web-app>

    <servlet>
        ...
    </servlet>

    <servlet-mapping>
        <servlet-name>...</servlet-name>
        <url-pattern>/*</url-pattern>
    </servlet-mapping>

    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Secure Content</web-resource-name>
            <url-pattern>/test-secure/*</url-pattern>
            <url-pattern>/test/secure/2/*</url-pattern>
            <http-method>GET</http-method>
            <http-method>POST</http-method>
        </web-resource-collection>
        <auth-constraint>
            <role-name>test-role</role-name>
        </auth-constraint>
        <user-data-constraint>
            <!-- 
                  Values: NONE, INTEGRAL, CONFIDENTIAL 
            -->
            <transport-guarantee>NONE</transport-guarantee> 
        </user-data-constraint>
    </security-constraint>

    <login-config>
        <!-- 
               Values: BASIC, DIGEST, FORM, CLIENT-CERT 
        -->
        <auth-method>BASIC</auth-method> 
        <realm-name>Test Authentication Realm</realm-name> <!-- optional, only useful for BASIC, DIGEST -->
    </login-config>

    <security-role>
        <role-name>test-role</role-name>
    </security-role>
</web-app>

Configuration Elements

<security-constraint>

A <security-constraint> tag protects a <web-resource-collection> so that access is granted only for roles in the <auth-constraint>.

Accessing <security-constraint> Metadata from Tomcat

Accessing <security-constraint> Metadata from Tomcat

<web-resource-collection>

Each <web-resource-collection> contains a name, any number of URL patterns specifying the URLs to protect, and any number of HTTP methods for which access should be restricted. For URL patterns you can use wildcards. If no <http-method> is specified, then all methods are protected.

<url-pattern>

<url-pattern> is relative to the context root.

For the example above, if we try to access http://localhost:8080/test-servlet/whatever, we are not challenged for user/password, and allowed access the resource. It is not secured. The container does not associate any security context with the thread. However, if we access http://localhost:8080/test-servlet/test-secure or http://localhost:8080/test-servlet/test-secure/whatever, we are challenged for credentials, and we are only allowed access if our user has the correct role ('test-role').

In JBoss 5.1, the decision on whether a request is authorized or not is taken in org.jboss.web.tomcat.security.JBossWebRealm. TODO update for EAP 6.

<http-method>

If no HTTP methods are named in the collection it means that all are protected.

<auth-constraint>

Specifying multiple roles

If more than one role has to be specified (with the semantics of allowing one role or another), the syntax is:

<web-app>
    <security-constraint>
        ...
        <auth-constraint>
            <role-name>RoleOne</role-name>
            <role-name>RoleTwo</role-name>
        </auth-constraint>
    </security-constraint>
</web-app>    

<user-data-constraint>, <transport-guarantee>

<user-data-constraint> specifies the requirements for the transport layer of the client to server connection (NONE | INTEGRAL | CONFIDENTIAL).

Specify CONFIDENTIAL when the application requires that data be transmitted so as to prevent other entities from observing the contents of the transmission.

Specify INTEGRAL when the application requires that the data be sent between client and server in such a way that it cannot be changed in transit.

Specify NONE to indicate that the container must accept the constrained requests on any connection, including an unprotected one.

In practice, Java EE servers treat the CONFIDENTIAL and INTEGRAL transport guarantee values identically, and both mean SSL.

A working example of a servlet that requests SSL/TSL transport layer security is available here:

https://github.com/NovaOrdis/playground/tree/master/jee/servlet/ssl-servlet

<login-config>

Specifying an Authentication Mechanism, JEE tutorial http://download.oracle.com/javaee/6/tutorial/doc/gkbaa.html#bncbn
http://download.oracle.com/javaee/1.4/tutorial/doc/Security5.html

The <login-config> element is used to specify the user authentication method to be used for access to web content, the realm in which the user will be authenticated, and, in the case of form-based login, additional attributes. When specified, the user must be authenticated before access to any resource that is constrained by a security constraint will be granted. <auth-method> specifies the authentication method for the Web application: BASIC, DIGEST, FORM or CLIENT-CERT. The realm-name specifies the realm name to use in HTTP BASIC and DIGEST authorization.

BASIC Authentication

A servlet protected with BASIC authentication:

https://github.com/NovaOrdis/playground/tree/master/jee/servlet/basic-authentication

FORM Authentication

Servlets can also perform authentication without relying on HTTP authentication, by using HTTP forms instead:

....
<login-config>
      <auth-method>FORM</auth-method>
      <form-login-config>
          <form-login-page>/loginpage.html</form-login-page>
          <form-error-page>/errorpage.html</form-error-page>
      </form-login-config>
</login-config>

The login page must include a form with special values to ensure the proper data is submitted to the server. The form must be a POST to the URL j_security_check with a username sent as j_username and a password sent as j_password.

Custom auth-method

TODO:

Custom auth-method And Tomcat Authenticator Valve https://home.feodorov.com:9443/wiki/Wiki.jsp?page=CustomAuthMethodAndTomcatAuthenticatorValve

Accessing <login-config> Metadata from Tomcat

Accessing <login-config> Metadata from Tomcat

Application Server-Specific Configuration

TODO

Conversation between Browser and Server for Authenticated Content

Sequence of Calls for BASIC Authentication

  • Unauthenticated request reaches BasicAuthenticator.invoke().
  • The valve looks up the Realm into the associated Context and gets a JBossWebRealm instance.
  • The valve gets the SecurityConstraint[[] from the JBossWebRealm instance.
  • The valve makes sure that security constrained resources are not cached:
                response.setHeader("Pragma", "No-cache");
                response.setHeader("Cache-Control", "no-cache");
                ...
                response.setHeader("Expires", DATE_ONE);
  • BasicAuthenticator.authenticate(...) gets invoked.
  • This one sends an "unauthorized" response (401) and an appropriate challenge ("WWW-Authenticate Basic realm="My Realm"").
  • The browser challenges the user for username/password and inserts an "authorization" MIME header with the Base64 encoded "<username>:<password>" pair (value similar to "Basic YWxpY2U6YWxpY2UxMjM=")
  • Request intercepted again by the BasicAuthenticator, which extracts the "authorization" MIME header and from it the user name and the password.
  • The valve calls the JBossWebRealm's authenticate(username, password).

For the theory behind this, see:

TODO:


HTTP Basic Authentication Protocol https://home.feodorov.com:9443/wiki/Wiki.jsp?page=HTTPBasicAuthentication#Protocol

Sequence of Calls for FORM Authentication

Valid for EAP 6.3.0.

  • Unauthenticated request reaches FormAuthenticator.invoke().
  • If there are no security constraints for this request - let it go through.
  • Determine whether authentication is required based on the security constraint identified for request.
  • Perform FormAuthenticator.authenticate(...).


  • If we're already authenticated (request.getUserPrincipal() is not null, return true.
  • If the request is not a request for the login page (ends in /j_security_check), save the request and forward it to the login page FormAuthenticator.forwardToLoginPage().
  • Continue here ...

Example of Selectively Protecting Different Resources for Access By Different Roles

TODO

Example of Selectively Protecting Different Resources for Access By Different Roles https://home.feodorov.com:9443/wiki/Wiki.jsp?page=web.xml-example1


Process: