This project has retired. For details please refer to its
Attic page.
HttpDigestAuthentication 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 import org.apache.archiva.redback.authentication.AuthenticationException;
23 import org.apache.archiva.redback.policy.MustChangePasswordException;
24 import org.apache.archiva.redback.users.User;
25 import org.apache.archiva.redback.users.UserManagerException;
26 import org.apache.commons.codec.binary.Base64;
27 import org.apache.archiva.redback.authentication.AuthenticationResult;
28 import org.apache.archiva.redback.authentication.TokenBasedAuthenticationDataSource;
29 import org.apache.archiva.redback.policy.AccountLockedException;
30 import org.apache.archiva.redback.users.UserManager;
31 import org.apache.archiva.redback.users.UserNotFoundException;
32 import org.apache.archiva.redback.integration.filter.authentication.HttpAuthenticationException;
33 import org.apache.archiva.redback.integration.filter.authentication.HttpAuthenticator;
34 import org.apache.commons.lang.StringUtils;
35 import org.springframework.stereotype.Service;
36
37 import javax.inject.Inject;
38 import javax.inject.Named;
39 import javax.servlet.http.HttpServletRequest;
40 import javax.servlet.http.HttpServletResponse;
41 import javax.servlet.http.HttpSession;
42 import java.io.IOException;
43
44
45
46
47
48
49 @Service("httpAuthenticator#digest")
50 public class HttpDigestAuthentication
51 extends HttpAuthenticator
52 {
53 @Inject
54 @Named(value = "userManager#default")
55 private UserManager userManager;
56
57
58
59
60 private int nonceLifetimeSeconds = 300;
61
62
63
64
65 private String digestKey = "OrycteropusAfer";
66
67 private String realm;
68
69 public String getId()
70 {
71 return HttpDigestAuthentication.class.getName();
72 }
73
74 public AuthenticationResult getAuthenticationResult( HttpServletRequest request, HttpServletResponse response )
75 throws AuthenticationException, AccountLockedException, MustChangePasswordException
76 {
77 HttpSession httpSession = request.getSession( true );
78 if ( isAlreadyAuthenticated( httpSession ) )
79 {
80 return getSecuritySession( httpSession ).getAuthenticationResult();
81 }
82
83 TokenBasedAuthenticationDataSource authDataSource = new TokenBasedAuthenticationDataSource();
84 String authHeader = request.getHeader( "Authorization" );
85
86
87 if ( authHeader == null )
88 {
89 authHeader = request.getHeader( "authorization" );
90 }
91
92 if ( ( authHeader != null ) && authHeader.startsWith( "Digest " ) )
93 {
94 String rawDigestHeader = authHeader.substring( 7 );
95
96 HttpDigestHeader digestHeader = new HttpDigestHeader();
97 digestHeader.parseClientHeader( rawDigestHeader, getRealm(), digestKey );
98
99
100 User user = findUser( digestHeader.username );
101 authDataSource.setPrincipal( user.getUsername() );
102
103 String serverSideHash = generateDigestHash( digestHeader, user.getPassword(), request.getMethod() );
104
105 if ( !StringUtils.equals( serverSideHash, digestHeader.response ) )
106 {
107 throw new HttpAuthenticationException( "Digest response was invalid." );
108 }
109 }
110
111 return super.authenticate( authDataSource, httpSession );
112 }
113
114 public User findUser( String username )
115 throws HttpAuthenticationException
116 {
117 try
118 {
119 return userManager.findUser( username );
120 }
121 catch ( UserNotFoundException e )
122 {
123 String msg = "Unable to find primary user '" + username + "'.";
124 log.error( msg, e );
125 throw new HttpAuthenticationException( msg, e );
126 }
127 catch ( UserManagerException e )
128 {
129 log.error( "issue find user {}, message: {}", username, e.getMessage(), e );
130 throw new HttpAuthenticationException( "issue find user " + username + ", message: " + e.getMessage(), e );
131 }
132 }
133
134
135
136
137
138
139
140
141
142
143 public void challenge( HttpServletRequest request, HttpServletResponse response, String realmName,
144 AuthenticationException exception )
145 throws IOException
146 {
147
148 StringBuilder authHeader = new StringBuilder();
149 authHeader.append( "Digest " );
150
151 authHeader.append( "realm=\"" ).append( realmName ).append( "\"" );
152
153
154
155 authHeader.append( ", nonce=\"" );
156 long timestamp = System.currentTimeMillis() + ( nonceLifetimeSeconds * 1000 );
157
158 String hraw = String.valueOf( timestamp ) + ":" + digestKey;
159 String rawnonce = String.valueOf( timestamp ) + ":" + Digest.md5Hex( hraw );
160 authHeader.append( Base64.encodeBase64( rawnonce.getBytes() ) );
161 authHeader.append( "\"" );
162
163
164
165 authHeader.append( ", qop=\"auth\"" );
166
167
168
169
170 if ( exception instanceof NonceExpirationException )
171 {
172 authHeader.append( ", stale=\"true\"" );
173 }
174
175
176
177
178 response.addHeader( "WWW-Authenticate", authHeader.toString() );
179 response.sendError( HttpServletResponse.SC_UNAUTHORIZED, exception.getMessage() );
180 }
181
182 private String generateDigestHash( HttpDigestHeader digestHeader, String password, String httpMethod )
183 {
184 String a1 = Digest.md5Hex( digestHeader.username + ":" + realm + ":" + password );
185 String a2 = Digest.md5Hex( httpMethod + ":" + digestHeader.uri );
186
187 String digest;
188
189 if ( StringUtils.isEmpty( digestHeader.qop ) )
190 {
191 digest = a1 + ":" + digestHeader.nonce + ":" + a2;
192 }
193 else if ( StringUtils.equals( "auth", digestHeader.qop ) )
194 {
195 digest = a1 + ":" + digestHeader.nonce + ":" + digestHeader.nc + ":" + digestHeader.cnonce + ":"
196 + digestHeader.qop + ":" + a2;
197 }
198 else
199 {
200 throw new IllegalStateException(
201 "Http Digest Parameter [qop] with value of [" + digestHeader.qop + "] is unsupported." );
202 }
203
204 return Digest.md5Hex( digest );
205 }
206
207 public String getRealm()
208 {
209 return realm;
210 }
211
212 public void setRealm( String realm )
213 {
214 this.realm = realm;
215 }
216
217 }