Apache Tomcat/6.0.18 — Error report

Implementing HTTP Digest Authentication in Java

I recently had to implement my own version of RFC 2617 which addresses the digest authentication in http protocol. This RFC is an improvement over RFC 2069 which was the previous version of Digest Access authentication. However RFC 2617 adds some additional security features such as quality of protection (qop) to try to counter re-play attacks.

Generally in java world, people don’t implement this themselves, most commonly used HTTP authentication is container managed. So you just configure your web.xml to identify that you want to use BASIC or DIGEST method, and then you configure a JNDI or other data-sources where the container picks up the passwords from, and that’s it.

Most people don’t have to write any code. The container managed Digest Access Authentication is pretty limited. It doesn’t allow you too much room to customize the behaviour, for example if you want to filter by IP addresses and only apply Digest Authentication to specific IP addresses only. Most applications don’t have these kind of customized requirements, however some do.

Since Digest Authentication is not that widely used yet, its hard to find a good implementation of it. Even Tomcat up-till 6.0 has not supported for example a pre-emptive digest authentication (I heard in Tomcat 7.x it’s supported but i haven’t checked it out yet). Most clients at the time of this writing have broken digest auth support (cURL comes to mind)

So when i needed to implement this in a specific way i had to write my own implementation of the RFC. i am just blogging about it to help you get it done faster if you have such a need.

Lets start with a brief introduction Here is how a typical HTTP Digest Auth would work. As you know in HTTP Digest Auth , unlike the Basic Authentication, no password is every exchanged between server and the client, instead the server sends a challenge to the client, the client sends back a encoded response based on username, password and server challenge, and the server then verifies if the client’s response is correct according to the challenge

Читайте также:  Doiso ru login index php

1) Client would request a resource i.e.

GET /HTTPDigestServer/HttpDigestAuth?username=usm

2) Server would send back an HTTP 401 indicating it’s a protected resource and needs authorization. In addition to sending back a 401 the Server will include an HTTP header called WWW-Authenticate, in this header there will be a field called “nonce” which basically is a challenge from the server. In addition to nonce , server optionally include a field called qop, which basically determines which algorithm will be used by client to calculate the response.

The possible values of qop are auth and auth-int. Server can also decide to not include this field, in which case the response will be calculated by the client in the old RFC 2069 style.

HTTP/1.1 401 Unauthorized Server: Apache-Coyote/1.1 WWW-Authenticate: Digest realm="abc.com",qop=auth,nonce="e986ce80f6d95a4cd4958d78e381fac0",opaque="b7d414d7663f03f9aa8eccf7204a0d43" Content-Type: text/html;charset=utf-8 Content-Length: 954 Date: Mon, 11 Jun 2012 18:05:09 GMT     

HTTP Status 401 -

type Status report

message

description This request requires HTTP authentication ().

Apache Tomcat/6.0.18

3) Client will then calculate a few hashes, combine them to create another hash called “response” this will be sent in a HTTP header called Authorization along with some other fields for example

GET /HTTPDigestServer/HttpDigestAuth?username=usm HTTP/1.1 Host: 127.0.0.1:8888 Connection: keep-alive Authorization: Digest username="usm", realm="abc.com", nonce="464586d93e858f45e59b4cb8e83ce89f", uri="/HTTPDigestServer/HttpDigestAuth?username=usm", response="598efaca64f9e7f02d92a13c50e74ad0", opaque="9dfa6fe2f0325895ece2bbab4a4837bd", qop=auth, nc=00000003, cnonce="c4020839a1c2ccb6" User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_7_4) AppleWebKit/536.5 (KHTML, like Gecko) Chrome/19.0.1084.54 Safari/536.5 Accept: text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8 Accept-Encoding: gzip,deflate,sdch Accept-Language: en-US,en;q=0.8 Accept-Charset: ISO-8859-1,utf-8;q=0.7,*;q=0.3 Cookie: JSESSIONID=272EAF671C64242C240D2D08F690839C

The server then verifies if the response value is correct or not. You can read the details of how the calculations are done on the nice wikipedia article here.

Читайте также:  Html растянуть ячейки таблицы

You can find below a sample Java Servlet which does the server side work of digest authentication. This servlet supports the qop = auth, auth-int and also not specifying the qop.

It also supports pre-emptive digest authentication which allows you to use a nonce for upto a minute, without having to re-authenticate, this can save you network traffic even though it can be a bad idea at times.

Also the strength of the HTTP digest authentication is how strong your nonce calculation is, for this sample implementation i am using a very simple nonce generation scheme. You can also download the code below as the java file here, the gist link to the file is https://gist.github.com/2912088

Share this:

Источник

Digest Authentication

This section provides details on how Spring Security provides support for Digest Authentication, which is provided DigestAuthenticationFilter .

You should not use Digest Authentication in modern applications, because it is not considered to be secure. The most obvious problem is that you must store your passwords in plaintext or an encrypted or MD5 format. All of these storage formats are considered insecure. Instead, you should store credentials by using a one way adaptive password hash (bCrypt, PBKDF2, SCrypt, and others), which is not supported by Digest Authentication.

Digest Authentication tries to solve many of the weaknesses of Basic authentication, specifically by ensuring credentials are never sent in clear text across the wire. Many browsers support Digest Authentication.

The standard governing HTTP Digest Authentication is defined by RFC 2617, which updates an earlier version of the Digest Authentication standard prescribed by RFC 2069. Most user agents implement RFC 2617. Spring Security’s Digest Authentication support is compatible with the “auth” quality of protection ( qop ) prescribed by RFC 2617, which also provides backward compatibility with RFC 2069. Digest Authentication was seen as a more attractive option if you need to use unencrypted HTTP (no TLS or HTTPS) and wish to maximize security of the authentication process. However, everyone should use HTTPS.

Читайте также:  Create modern website using html css and bootstrap

Central to Digest Authentication is a “nonce”. This is a value the server generates. Spring Security’s nonce adopts the following format:

base64(expirationTime + ":" + md5Hex(expirationTime + ":" + key)) expirationTime: The date and time when the nonce expires, expressed in milliseconds key: A private key to prevent modification of the nonce token

You need to ensure that you configure insecure plain text Password Storage using NoOpPasswordEncoder . (See the NoOpPasswordEncoder class in the Javadoc.) The following provides an example of configuring Digest Authentication with Java Configuration:

@Autowired UserDetailsService userDetailsService; DigestAuthenticationEntryPoint entryPoint() < DigestAuthenticationEntryPoint result = new DigestAuthenticationEntryPoint(); result.setRealmName("My App Realm"); result.setKey("3028472b-da34-4501-bfd8-a355c42bdf92"); >DigestAuthenticationFilter digestAuthenticationFilter() < DigestAuthenticationFilter result = new DigestAuthenticationFilter(); result.setUserDetailsService(userDetailsService); result.setAuthenticationEntryPoint(entryPoint()); >@Bean public SecurityFilterChain filterChain(HttpSecurity http) throws Exception < http // . .exceptionHandling(e ->e.authenticationEntryPoint(authenticationEntryPoint())) .addFilterBefore(digestFilter()); return http.build(); >

Apache®, Apache Tomcat®, Apache Kafka®, Apache Cassandra™, and Apache Geode™ are trademarks or registered trademarks of the Apache Software Foundation in the United States and/or other countries. Java™, Java™ SE, Java™ EE, and OpenJDK™ are trademarks of Oracle and/or its affiliates. Kubernetes® is a registered trademark of the Linux Foundation in the United States and other countries. Linux® is the registered trademark of Linus Torvalds in the United States and other countries. Windows® and Microsoft® Azure are registered trademarks of Microsoft Corporation. “AWS” and “Amazon Web Services” are trademarks or registered trademarks of Amazon.com Inc. or its affiliates. All other trademarks and copyrights are property of their respective owners and are only mentioned for informative purposes. Other names may be trademarks of their respective owners.

Источник

Оцените статью