//
//  ========================================================================
//  Copyright (c) 1995-2020 Mort Bay Consulting Pty Ltd and others.
//  ========================================================================
//  All rights reserved. This program and the accompanying materials
//  are made available under the terms of the Eclipse Public License v1.0
//  and Apache License v2.0 which accompanies this distribution.
//
//      The Eclipse Public License is available at
//      http://www.eclipse.org/legal/epl-v10.html
//
//      The Apache License v2.0 is available at
//      http://www.opensource.org/licenses/apache2.0.php
//
//  You may elect to redistribute this code under either of these licenses.
//  ========================================================================
//

[[configuring-security-authentication]]
=== Authentication and Authorization

There are two aspects to securing a web application(or context) within the Jetty server:

Authentication::
  The web application can be configured with a mechanism to determine the identity of the user.
  This is configured by a mix of standard declarations and jetty specific mechanisms and is covered in this section.
Authorization::
  Once the identify of the user is known (or not known), the web application can be configured via standard descriptors with security constraints that declare what resources that user may access.

==== Configuring an Authentication mechanism

Jetty server supports several standard authentication mechanisms: http://en.wikipedia.org/wiki/Basic_access_authentication[BASIC]; http://en.wikipedia.org/wiki/Digest_authentication[DIGEST]; http://en.wikipedia.org/wiki/Form-based_authentication[FORM]; CLIENT-CERT; and other mechanisms can be plugged in using the extensible http://docs.oracle.com/cd/E19462-01/819-6717/gcszc/index.html[JASPI] or http://en.wikipedia.org/wiki/SPNEGO[SPNEGO] mechanisms.

Internally, configuring an authentication mechanism is done by setting an instance of a the link:{JDURL}/org/eclipse/jetty/security/Authenticator.html[Authenticator] interface onto the link:{JDURL}/org/eclipse/jetty/security/SecurityHandler.html[SecurityHandler] of the context, but in most cases it is done by declaring a `<login-config>` element in the standard web.xml descriptor or via annotations.

Below is an example taken from the link:{GITBROWSEURL}/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml?h=release-9[jetty-test-webapp web.xml] that configures BASIC authentication:

[source, xml, subs="{sub-order}"]
----
  <login-config>
    <auth-method>BASIC</auth-method>
    <realm-name>Test Realm</realm-name>
  </login-config>

----

The link:{GITBROWSEURL}/tests/test-webapps/test-jetty-webapp/src/main/webapp/WEB-INF/web.xml?h=release-9[jetty-test-webapp web.xml] also includes commented out examples of other DIGEST and FORM configuration:

[source, xml, subs="{sub-order}"]
----
  <login-config>
    <auth-method>FORM</auth-method>
    <realm-name>Test Realm</realm-name>
    <form-login-config>
       <form-login-page>/logon.html?param=test</form-login-page>
       <form-error-page>/logonError.html?param=test</form-error-page>
    </form-login-config>
  </login-config>

----

With FORM Authentication, you must also configure URLs of pages to generate a login form and handle errors.
Below is a simple HTML form from the link:{GITBROWSEURL}/tests/test-webapps/test-jetty-webapp/src/main/webapp/logon.html?h=release-9[test webapp logon.html]:

[source, xml, subs="{sub-order}"]
----
<HTML>
<H1>FORM Authentication demo</H1>
<form method="POST" action="j_security_check">
<table border="0" cellspacing="2" cellpadding="1">
<tr>
  <td>Username:</td>
  <td><input size="12" value="" name="j_username" maxlength="25" type="text"></td>
</tr>
<tr>
  <td>Password:</td>
  <td><input size="12" value="" name="j_password" maxlength="25" type="password"></td>
</tr>
<tr>
  <td colspan="2" align="center">
    <input name="submit" type="submit" value="Login">
  </td>
</tr>
</table>
</form>
</HTML>

----

The Authentication mechanism declared for a context / web application defines how the server obtain authentication credentials from the
client, but it does not define how the server checks if those credentials are valid.
To check credentials, the server and/or context also need to be configured with a link:{JDURL}/org/eclipse/jetty/security/LoginService.html[LoginService] instance, which may be matched by the declared realm-name.

[[security-realms]]
==== Security Realms

Security realms allow you to secure your web applications against unauthorized access.
Protection is based on authentication that identifies who is requesting access to the webapp and access control that restricts what can be accessed and how it is accessed within the webapp.

A webapp statically declares its security requirements in its web.xml file.
Authentication is controlled by the `<login-config>` element.
Access controls are specified by `<security-constraint>` and `<security-role-ref>` elements.
When a request is received for a protected resource, the web container checks if the user performing the request is authenticated, and if the user has a role assignment that permits access to the requested resource.

The Servlet Specification does not address how the static security information in the `WEB-INF/web.xml` file is mapped to the runtime environment of the container.
For Jetty, the link:{JDURL}/org/eclipse/jetty/security/LoginService.html[LoginService] performs this function.

A `LoginService` has a unique name, and gives access to information about a set of users.
Each user has authentication information (e.g. a password) and a set of roles associated with him/herself.

You may configure one or many different LoginServices depending on your needs.
A single realm would indicate that you wish to share common security information across all of your web applications.
Distinct realms allow you to partition your security information webapp by webapp.

When a request to a web application requires authentication or authorization, Jetty will use the `<realm-name>` sub-element inside `<login-config>` element in the web.xml file to perform an _exact match_ to a LoginService.

==== Scoping Security Realms

A `LoginService` has a unique name, and is composed of a set of users.
Each user has authentication information (for example, a password) and a set of roles associated with him/herself.
You can configure one or many different realms depending on your needs.

* Configure a single LoginService to share common security information across all of your web applications.
* Configure distinct LoginServices to partition your security information webapp by webapp.

===== Globally Scoped

A LoginService is available to all web applications on a Server instance if you add it as a bean to the Server.
Such a definition would go into an xml file in your `${jetty.base}/etc` directory, e.g. `${jetty.base}/etc/my-realm.xml` and you would add this xml file to the execution path via `start.ini` or `start.d` (you may want to review the material in the link:#startup[Starting Jetty] chapter).
Here's an example of an xml file that defines an in-memory type of LoginService called the link:{JDURL}/org/eclipse/jetty/security/HashLoginService.html[HashLoginService]:

[source, xml, subs="{sub-order}"]
----

<Configure id="Server" class="org.eclipse.jetty.server.Server">
  <Call name="addBean">
    <Arg>
      <New class="org.eclipse.jetty.security.HashLoginService">
        <Set name="name">Test Realm</Set>
        <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
        <Set name="hotReload">true</Set>
      </New>
    </Arg>
  </Call>
</Configure>


----

If you define more than one `LoginService` on a Server, you will need to specify which one you want used for each context.
You can do that by telling the context the name of the `LoginService`, or passing it the `LoginService` instance.
Here's an example of doing both of these, using a link:#deployable-descriptor-file[context xml file]:

[source, xml, subs="{sub-order}"]
----

<Configure class="org.eclipse.jetty.webapp.WebAppContext">
 <Get name="securityHandler">
   <!-- Either: -->
   <Set name="loginService">
     <New class="org.eclipse.jetty.security.HashLoginService">
           <Set name="name">Test Realm</Set>
     </New>
   </Set>

   <!-- or if you defined a LoginService called "Test Realm" in jetty.xml : -->
   <Set name="realmName">Test Realm</Set>

 </Get>


----

===== Per-Webapp Scoped

Alternatively, you can define a `LoginService` for just a single web application.
Here's how to define the same HashLoginService, but inside a link:#deployable-descriptor-file[context xml file]:

[source, xml, subs="{sub-order}"]
----

<Configure class="org.eclipse.jetty.webapp.WebAppContext">
  <Set name="contextPath">/test</Set>
  <Set name="war"><SystemProperty name="jetty.home" default="."/>/webapps/test</Set>
  <Get name="securityHandler">
    <Set name="loginService">
      <New class="org.eclipse.jetty.security.HashLoginService">
            <Set name="name">Test Realm</Set>
            <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
      </New>
    </Set>
  </Get>
</Configure>


----

Jetty provides a number of different `LoginService` types which can be seen in the next section.

[[configuring-login-service]]
==== Configuring a LoginService

A link:{JDURL}/org/eclipse/jetty/security/LoginService.html[`LoginService`] instance is required by each context/webapp that has a authentication mechanism, which is used to check the validity of the username and credentials collected by the authentication mechanism. Jetty provides the following implementations of `LoginService`:

link:{JDURL}/org/eclipse/jetty/security/HashLoginService.html[HashLoginService]::
  A user realm that is backed by a hash map that is filled either programatically or from a Java properties file.
link:{JDURL}/org/eclipse/jetty/security/JDBCLoginService.html[JDBCLoginService]::
  Uses a JDBC connection to an SQL database for authentication
link:{JDURL}/org/eclipse/jetty/plus/security/DataSourceLoginService.html[DataSourceLoginService]::
  Uses a JNDI defined   http://docs.oracle.com/javase/7/docs/api/javax/sql/DataSource.html[DataSource] for authentication
link:{JDURL}/org/eclipse/jetty/jaas/JAASLoginService.html[JAASLoginService]::
  Uses a http://en.wikipedia.org/wiki/Java_Authentication_and_Authorization_Service[JAAS] provider for authentication; see the section on
  link:#jaas-support[JAAS support] for more information
link:{JDURL}/org/eclipse/jetty/security/SpnegoLoginService.html[SpnegoLoginService]::
  http://en.wikipedia.org/wiki/SPNEGO[SPNEGO] Authentication; see the section on link:#spnego-support[SPNEGO support] for more information.

An instance of a `LoginService` can be matched to a context/webapp by:

* A `LoginService` instance may be set directly on the `SecurityHandler` instance via embedded code or IoC XML
* Matching the realm-name defined in web.xml with the name of a `LoginService` instance that has been added to the Server instance as a dependent bean
* If only a single `LoginService` instance has been set on the Server then it is used as the login service for the context

[[hash-login-service]]
===== HashLoginService

The `HashLoginService` is a simple and efficient login service that loads usernames, credentials and roles from a Java properties file in the format:

[source,properties]
----

username: password[,rolename ...]

----

Where:

username::
  is the user's unique identity
password::
  is the user's (possibly obfuscated or MD5 encrypted) password;
rolename::
  is a role of the user

For example:

[source,properties]
----

admin: CRYPT:ad1ks..kc.1Ug,server-administrator,content-administrator,admin
other: OBF:1xmk1w261u9r1w1c1xmq
guest: guest,read-only

----

You configure the `HashLoginService` with a name and a reference to the location of the properties file:

[source, xml, subs="{sub-order}"]
----

<Item>
<New class="org.eclipse.jetty.security.HashLoginService">
  <Set name="name">Test Realm</Set>
  <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
</New>
</Item>

----

You can also configure it to reload the configuration file when changes to it are detected.

[source, xml, subs="{sub-order}"]
----

<New class="org.eclipse.jetty.security.HashLoginService">
    <Set name="name">Test Realm</Set>
    <Set name="config"><SystemProperty name="jetty.home" default="."/>/etc/realm.properties</Set>
    <Set name="hotReload">true</Set>
    <Call name="start"></Call>
  </New>

----

[[jdbc-login-service]]
===== JDBCLoginService

In this implementation, authentication and role information is stored in a database accessed via JDBC.
A properties file defines the JDBC connection and database table information.
Here is an example of a properties file for this realm implementation:

[source,properties]
----

jdbcdriver = org.gjt.mm.mysql.Driver
url = jdbc:mysql://localhost/jetty
username = jetty
password = jetty
usertable = users
usertablekey = id
usertableuserfield = username
usertablepasswordfield = pwd
roletable = roles
roletablekey = id
roletablerolefield = role
userroletable = user_roles
userroletableuserkey = user_id
userroletablerolekey = role_id
cachetime = 300

----

The format of the database tables is (pseudo-sql):

[source,sql]
----

users
(
  id integer PRIMARY KEY,
  username varchar(100) NOT NULL UNIQUE KEY,
  pwd varchar(50) NOT NULL
);
user_roles
(
  user_id integer NOT NULL,
  role_id integer NOT NULL,
  UNIQUE KEY (user_id, role_id),
  INDEX(user_id)
);
roles
(
  id integer PRIMARY KEY,
  role varchar(100) NOT NULL UNIQUE KEY
);

----

Where:

* *users* is a table containing one entry for every user consisting of:
+
id::
  the unique identity of a user
user::
  the name of the user
pwd::
  the user's password (possibly obfuscated or MD5 encrypted)
* *user-roles* is a table containing one row for every role granted to a
user:
+
user_id::
  the unique identity of the user
role_id::
  the role for a user
* *roles* is a a table containing one role for every role in the system:
+
id::
  the unique identifier of a role
role::
  a human-readable name for a role

If you want to use obfuscated, MD5 hashed or encrypted passwords the `pwd` column of the `users` table must be large enough to hold the obfuscated, hashed or encrypted password text plus the appropriate prefix.

You define a `JDBCLoginService` with the name of the realm and the location of the properties file describing the database:

[source, xml, subs="{sub-order}"]
----
<New class="org.eclipse.jetty.security.JDBCLoginService">
  <Set name="name">Test JDBC Realm</Set>
  <Set name="config">etc/jdbcRealm.properties</Set>
</New>
----

==== Authorization

As far as the https://jcp.org/en/jsr/detail?id=340[Servlet Specification] is concerned, authorization is based on roles.
As we have seen, a `LoginService` associates a user with a set of roles.
When a user requests a resource that is access protected, the `LoginService` will be asked to authenticate the user if they are not already, and then asked to confirm if that user possesses one of the roles permitted access to the resource.

Until Servlet 3.1, role-based authorization could define:

* Access granted to a set of named roles:

[source, xml, subs="{sub-order}"]
----
<security-constraint>
  <web-resource-collection>
    <web-resource-name>Foo Admin Data</web-resource-name>
    <url-pattern>/foo/admin/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>admin</role-name>
    <role-name>manager</role-name>
  </auth-constraint>
</security-constraint>
----

* Access totally forbidden, regardless of role:

[source, xml, subs="{sub-order}"]
----
<security-constraint>
  <web-resource-collection>
    <web-resource-name>Foo Protected Data</web-resource-name>
    <url-pattern>/foo/protected/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
  </auth-constraint>
</security-constraint>
----
* Access granted to a user in any of the roles defined in the effective `web.xml`.
This is indicated by the special value of `*` for the `<role-name>` of a `<auth-constraint>` in the `<security-constraint>`:

[source, xml, subs="{sub-order}"]
----
<security-constraint>
  <web-resource-collection>
    <web-resource-name>Foo Role Data</web-resource-name>
    <url-pattern>/foo/role/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>*</role-name>
  </auth-constraint>
</security-constraint>
----

Servlet 3.1 introduced an additional authorization:

* Access granted to any user who is authenticated, regardless of roles.
This is indicated by the special value of `**` for the `<role-name>` of a `<auth-constraint>` in the `<security-constraint>`:

[source, xml, subs="{sub-order}"]
----
<security-constraint>
  <web-resource-collection>
    <web-resource-name>Foo Authenticated Data</web-resource-name>
    <url-pattern>/foo/authenticated/*</url-pattern>
  </web-resource-collection>
  <auth-constraint>
    <role-name>**</role-name>
  </auth-constraint>
</security-constraint>
----

Additionally, when configuring your security constraints you can protect various HTTP methods as well, such as `PUT`, `GET`, `POST`, `HEAD` or `DELETE`.
This is done by adding the method you want to protect as a `<http-method>` in the `<web-resource-collection>`.
You can then define roles that should be able to perform these protected methods in an `<auth-constraint>`:

[source, xml, subs="{sub-order}"]
----
<security-constraint>
  <web-resource-collection>
    <web-resource-name>Foo Authenticated Data</web-resource-name>
    <url-pattern>/foo/authenticated/*</url-pattern>
    <http-method>DELETE</http-method>
    <http-method>POST</http-method>
  </web-resource-collection>
  <auth-constraint>
    <role-name>admin</role-name>
  </auth-constraint>
</security-constraint>
----

In the above example, only users with an `admin` role will be able to perform `DELETE` or `POST` methods.

===== Configuring Authorization with Context XML Files

While the examples above show configuration of Authorization in a `web.xml` file, they can also be configured as part of the link#link:#deployable-descriptor-file[context xml file] for a web application.
This is especially helpful if authorization needs change over time and need updated without re-packaging the whole web app.

To do this, we add a section for security constraints into the context xml file for our web app as part of the `securityHandler`.
In the example below, a `HashLoginService` is defined with authorization being granted too `foo/*` paths to users with the `admin` and `manager` roles.

[source, xml, subs="{sub-order}"]
----
<Configure id="testWebapp" class="org.eclipse.jetty.webapp.WebAppContext">
  <Get name="securityHandler">
    <Set name="realmName">Test Realm</Set>
    <Set name="authMethod">BASIC</Set>
    <Call name="addConstraintMapping">
      <Arg>
         <New class="org.eclipse.jetty.security.ConstraintMapping">
            <Set name="pathSpec">/foo/*</Set>
            <Set name="constraint">
              <New class="org.eclipse.jetty.util.security.Constraint">
                  <Set name="name">Foo Auth</Set>
                  <Set name="authenticate">true</Set>
                  <Set name="roles">
                    <Array type="java.lang.String">
                      <Item>admin</Item>
                      <Item>manager</Item>
                    </Array>
                  </Set>
              </New>
            </Set>
         </New>
      </Arg>
    </Call>
    <Set name="loginService">
      <New class="org.eclipse.jetty.security.HashLoginService">
        <Set name="name">Test Realm</Set>
        <Set name="config">/src/tmp/small-security-test/realm.properties</Set>
      </New>
    </Set>
  </Get>
</Configure>
----

If roles changed in the future, administrators could easily change this context xml file without having to edit the contents of the web app at all.

==== Authentication and Authorization with Embedded Jetty

In addition to the distribution, security can be defined as part of an embedded implementation as well.
Below is an example which, like the one above, sets up a server with a `HashLoginService` and adds security constraints to restrict access based on roles.

[source, java, subs="{sub-order}"]
----
include::{SRCDIR}/examples/embedded/src/main/java/org/eclipse/jetty/embedded/SecuredHelloHandler.java[]
----
