View Javadoc

1   package com.bradmcevoy.http;
2   
3   import com.bradmcevoy.http.http11.auth.BasicAuthHandler;
4   import com.bradmcevoy.http.http11.auth.DigestAuthenticationHandler;
5   import com.bradmcevoy.http.http11.auth.NonceProvider;
6   import java.util.ArrayList;
7   import java.util.Collections;
8   import java.util.Iterator;
9   import java.util.List;
10  import org.slf4j.Logger;
11  import org.slf4j.LoggerFactory;
12  
13  /**
14   *
15   * @author brad
16   */
17  public class AuthenticationService {
18  
19      private static final Logger log = LoggerFactory.getLogger( AuthenticationService.class );
20      private List<AuthenticationHandler> authenticationHandlers;
21      private List<AuthenticationHandler> extraHandlers;
22      private List<AuthenticationHandler> allHandlers;
23      private boolean disableBasic;
24      private boolean disableDigest;
25  
26      /**
27       * Creates a AuthenticationService using the given handlers. Use this if
28       * you don't want the default of a BasicAuthHandler and a DigestAuthenticationHandler
29       *
30       * @param authenticationHandlers
31       */
32      public AuthenticationService( List<AuthenticationHandler> authenticationHandlers ) {
33          this.authenticationHandlers = authenticationHandlers;
34          setAllHandlers();
35      }
36  
37      /**
38       * Creates basic and digest handlers with the given NonceProvider
39       * 
40       * @param nonceProvider
41       */
42      public AuthenticationService( NonceProvider nonceProvider ) {
43          AuthenticationHandler digest = new DigestAuthenticationHandler( nonceProvider );
44          AuthenticationHandler basic = new BasicAuthHandler();
45  
46          authenticationHandlers = new ArrayList<AuthenticationHandler>();
47          authenticationHandlers.add( basic );
48          authenticationHandlers.add( digest );
49          setAllHandlers();
50      }
51  
52      /**
53       * Creates with Basic and Digest handlers
54       *
55       */
56      public AuthenticationService() {
57          AuthenticationHandler digest = new DigestAuthenticationHandler();
58          AuthenticationHandler basic = new BasicAuthHandler();
59          authenticationHandlers = new ArrayList<AuthenticationHandler>();
60          authenticationHandlers.add( basic );
61          authenticationHandlers.add( digest );
62          setAllHandlers();
63      }
64  
65      public void setDisableBasic( boolean b ) {
66          if( b ) {
67              Iterator<AuthenticationHandler> it = this.authenticationHandlers.iterator();
68              while( it.hasNext() ) {
69                  AuthenticationHandler hnd = it.next();
70                  if( hnd instanceof BasicAuthHandler ) {
71                      it.remove();
72                  }
73              }
74          }
75          disableBasic = b;
76          setAllHandlers();
77      }
78  
79      public boolean isDisableBasic() {
80          return disableBasic;
81      }
82  
83      public void setDisableDigest( boolean b ) {
84          if( b ) {
85              Iterator<AuthenticationHandler> it = this.authenticationHandlers.iterator();
86              while( it.hasNext() ) {
87                  AuthenticationHandler hnd = it.next();
88                  if( hnd instanceof DigestAuthenticationHandler ) {
89                      it.remove();
90                  }
91              }
92          }
93          disableDigest = b;
94          setAllHandlers();
95      }
96  
97      public boolean isDisableDigest() {
98          return disableDigest;
99      }
100 
101     /**
102      * Looks for an AuthenticationHandler which supports the given resource and
103      * authorization header, and then returns the result of that handler's
104      * authenticate method.
105      *
106      * Returns null if no handlers support the request
107      *
108      * @param resource
109      * @param request
110      * @return - null if no authentication was attempted. Otherwise, an AuthStatus
111      * object containing the Auth object and a boolean indicating whether the
112      * login succeeded
113      */
114     public AuthStatus authenticate( Resource resource, Request request ) {
115         log.trace( "authenticate" );
116         Auth auth = request.getAuthorization();
117         boolean preAuthenticated = ( auth != null && auth.getTag() != null );
118         if( preAuthenticated ) {
119             log.trace( "request is pre-authenticated" );
120             return new AuthStatus( auth, false );
121         }
122         for( AuthenticationHandler h : allHandlers ) {
123             if( h.supports( resource, request ) ) {
124                 Object loginToken = h.authenticate( resource, request );
125                 if( loginToken == null ) {
126                     log.warn( "authentication failed by AuthenticationHandler:" + h.getClass() );
127                     return new AuthStatus( auth, true );
128                 } else {
129                     if( log.isTraceEnabled() ) {
130                         log.trace( "authentication passed by: " + h.getClass() );
131                     }
132                     if( auth == null ) { // some authentication handlers do not require an Auth object
133                         auth = new Auth( Auth.Scheme.FORM, null, loginToken );
134                         request.setAuthorization( auth );
135                     }
136                     auth.setTag( loginToken );
137                 }
138                 return new AuthStatus( auth, false );
139             }
140         }
141         return null;
142     }
143 
144     /**
145      * Generates a list of http authentication challenges, one for each
146      * supported authentication method, to be sent to the client.
147      *
148      * @param resource - the resoruce being requested
149      * @param request - the current request
150      * @return - a list of http challenges
151      */
152     public List<String> getChallenges( Resource resource, Request request ) {
153         List<String> challenges = new ArrayList<String>();
154         for( AuthenticationHandler h : allHandlers ) {
155             if( h.isCompatible( resource ) ) {
156                 log.debug( "challenge for auth: " + h.getClass() );
157                 String ch = h.getChallenge( resource, request );
158                 challenges.add( ch );
159             } else {
160                 log.debug( "not challenging for auth: " + h.getClass() + " for resource type: " + (resource == null ? "" : resource.getClass()) );
161             }
162         }
163         return challenges;
164     }
165 
166     public List<AuthenticationHandler> getAuthenticationHandlers() {
167         return allHandlers;
168     }
169 
170     public List<AuthenticationHandler> getExtraHandlers() {
171         return extraHandlers;
172     }
173 
174     public void setExtraHandlers( List<AuthenticationHandler> extraHandlers ) {
175         this.extraHandlers = extraHandlers;
176         setAllHandlers();
177     }
178 
179     /**
180      * Merge standard and extra handlers into single list
181      */
182     private void setAllHandlers() {
183         List<AuthenticationHandler> handlers = new ArrayList<AuthenticationHandler>();
184         if( authenticationHandlers != null ) {
185             handlers.addAll( authenticationHandlers );
186         }
187         if( extraHandlers != null ) {
188             handlers.addAll( extraHandlers );
189         }
190         this.allHandlers = Collections.unmodifiableList( handlers );
191     }
192 
193     public static class AuthStatus {
194 
195         public final Auth auth;
196         public final boolean loginFailed;
197 
198         public AuthStatus( Auth auth, boolean loginFailed ) {
199             this.auth = auth;
200             this.loginFailed = loginFailed;
201         }
202     }
203 }