This project has retired. For details please refer to its
Attic page.
HttpDigestHeader xref
1 package org.apache.archiva.redback.integration.filter.authentication.digest;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23 import org.apache.commons.codec.binary.Base64;
24 import org.apache.archiva.redback.integration.HttpUtils;
25 import org.apache.archiva.redback.integration.filter.authentication.HttpAuthenticationException;
26 import org.apache.commons.lang.StringUtils;
27 import org.slf4j.Logger;
28 import org.slf4j.LoggerFactory;
29 import org.springframework.context.annotation.Scope;
30 import org.springframework.stereotype.Service;
31
32 import java.util.Properties;
33
34
35
36
37
38
39
40 @Service( "httpClientHeader" )
41 @Scope( "prototype" )
42 public class HttpDigestHeader
43 {
44 private Logger log = LoggerFactory.getLogger( HttpDigestHeader.class );
45
46 public String username;
47
48 public String realm;
49
50 public String nonce;
51
52 public String uri;
53
54 public String response;
55
56 public String qop;
57
58 public String nc;
59
60 public String cnonce;
61
62 public void parseClientHeader( String rawHeader, String expectedRealm, String digestKey )
63 throws HttpAuthenticationException
64 {
65 Properties authHeaderProps = HttpUtils.complexHeaderToProperties( rawHeader, ",", "=" );
66
67 username = authHeaderProps.getProperty( "username" );
68 realm = authHeaderProps.getProperty( "realm" );
69 nonce = authHeaderProps.getProperty( "nonce" );
70 uri = authHeaderProps.getProperty( "uri" );
71 response = authHeaderProps.getProperty( "response" );
72 qop = authHeaderProps.getProperty( "qop" );
73 nc = authHeaderProps.getProperty( "nc" );
74 cnonce = authHeaderProps.getProperty( "cnonce" );
75
76
77 if ( StringUtils.isEmpty( username ) || StringUtils.isEmpty( realm ) || StringUtils.isEmpty( nonce )
78 || StringUtils.isEmpty( uri ) || StringUtils.isEmpty( response ) )
79 {
80 log.debug( "Missing mandatory fields: Raw Digest Header : [{}]", rawHeader );
81
82 throw new HttpAuthenticationException( "Missing mandatory digest fields per RFC2069." );
83 }
84
85
86 if ( !StringUtils.equals( expectedRealm, realm ) )
87 {
88 log.debug( "Realm name is invalid: expected [{}] but got [{}]", expectedRealm, realm );
89
90 throw new HttpAuthenticationException( "Response realm does not match expected realm." );
91 }
92
93
94 if ( StringUtils.equals( "auth", qop ) )
95 {
96 if ( StringUtils.isEmpty( nc ) || StringUtils.isEmpty( cnonce ) )
97 {
98 log.debug( "Missing mandatory qop fields: nc [{}] cnonce [{}]", nc, cnonce );
99
100 throw new HttpAuthenticationException( "Missing mandatory qop digest fields per RFC2617." );
101 }
102 }
103
104
105 if ( !Base64.isArrayByteBase64( nonce.getBytes() ) )
106 {
107 log.debug( "Nonce is not encoded in Base64: nonce [{}]", nonce );
108
109 throw new HttpAuthenticationException( "Response nonce is not encoded in Base64." );
110 }
111
112
113 String decodedNonce = new String( Base64.decodeBase64( nonce.getBytes() ) );
114 String nonceTokens[] = StringUtils.split( decodedNonce, ":" );
115
116
117 if ( nonceTokens.length != 2 )
118 {
119 log.debug( "Nonce format expected [2] elements, but got [{}] instead. Decoded nonce [{}]",
120 nonceTokens.length, decodedNonce );
121
122 throw new HttpAuthenticationException(
123 "Nonce format is invalid. " + "Received an unexpected number of sub elements." );
124 }
125
126
127 long nonceTimestamp = 0;
128
129 try
130 {
131 nonceTimestamp = Long.parseLong( nonceTokens[0] );
132 }
133 catch ( NumberFormatException e )
134 {
135 throw new HttpAuthenticationException( "Unexpected nonce timestamp." );
136 }
137
138
139 String expectedSignature = Digest.md5Hex( nonceTimestamp + ":" + digestKey );
140
141 if ( !StringUtils.equals( expectedSignature, nonceTokens[1] ) )
142 {
143 log.error( "Nonce parameter has been compromised." );
144
145 throw new HttpAuthenticationException( "Nonce parameter has been compromised." );
146 }
147 }
148 }