Merge with 2ad3c504ee5d73982c0ef23336276dc1fc9e165f
[pithos] / src / gr / ebs / gss / server / webdav / milton / GssAuthenticationService.java
1 /*
2  * Copyright 2011 Electronic Business Systems Ltd.
3  *
4  * This file is part of GSS.
5  *
6  * GSS is free software: you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation, either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * GSS is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with GSS.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 package gr.ebs.gss.server.webdav.milton;
20
21 import static gr.ebs.gss.server.configuration.GSSConfigurationFactory.getConfiguration;
22 import gr.ebs.gss.client.exceptions.RpcException;
23 import gr.ebs.gss.server.ejb.ExternalAPI;
24
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.Iterator;
28 import java.util.List;
29
30 import javax.naming.Context;
31 import javax.naming.InitialContext;
32 import javax.naming.NamingException;
33 import javax.rmi.PortableRemoteObject;
34
35 import org.slf4j.Logger;
36 import org.slf4j.LoggerFactory;
37
38 import com.bradmcevoy.http.Auth;
39 import com.bradmcevoy.http.AuthenticationHandler;
40 import com.bradmcevoy.http.AuthenticationService;
41 import com.bradmcevoy.http.Request;
42 import com.bradmcevoy.http.Resource;
43 import com.bradmcevoy.http.http11.auth.BasicAuthHandler;
44 import com.bradmcevoy.http.http11.auth.DigestAuthenticationHandler;
45
46
47 /**
48  * @author kman
49  *
50  */
51 public class GssAuthenticationService extends com.bradmcevoy.http.AuthenticationService{
52         private static final Logger log = LoggerFactory.getLogger( AuthenticationService.class );
53     private List<AuthenticationHandler> authenticationHandlers;
54     private List<AuthenticationHandler> extraHandlers;
55     private List<AuthenticationHandler> allHandlers;
56     private boolean disableBasic;
57     private boolean disableDigest;
58
59     /**
60      * Creates a AuthenticationService using the given handlers. Use this if
61      * you don't want the default of a BasicAuthHandler and a DigestAuthenticationHandler
62      *
63      * @param authenticationHandlers
64      */
65     public GssAuthenticationService( List<AuthenticationHandler> authenticationHandlers ) {
66         this.authenticationHandlers = authenticationHandlers;
67         setAllHandlers();
68     }
69
70
71     /**
72      * Creates with Basic and Digest handlers
73      *
74      */
75     public GssAuthenticationService() {
76         AuthenticationHandler digest = new com.bradmcevoy.http.http11.auth.DigestAuthenticationHandler();
77         AuthenticationHandler basic = new BasicAuthHandler();
78         authenticationHandlers = new ArrayList<AuthenticationHandler>();
79         authenticationHandlers.add( basic );
80         authenticationHandlers.add( digest );
81         setAllHandlers();
82     }
83
84     public void setDisableBasic( boolean b ) {
85         if( b ) {
86             Iterator<AuthenticationHandler> it = this.authenticationHandlers.iterator();
87             while( it.hasNext() ) {
88                 AuthenticationHandler hnd = it.next();
89                 if( hnd instanceof BasicAuthHandler ) {
90                     it.remove();
91                 }
92             }
93         }
94         disableBasic = b;
95         setAllHandlers();
96     }
97
98     public boolean isDisableBasic() {
99         return disableBasic;
100     }
101
102     public void setDisableDigest( boolean b ) {
103         if( b ) {
104             Iterator<AuthenticationHandler> it = this.authenticationHandlers.iterator();
105             while( it.hasNext() ) {
106                 AuthenticationHandler hnd = it.next();
107                 if( hnd instanceof DigestAuthenticationHandler ) {
108                     it.remove();
109                 }
110             }
111         }
112         disableDigest = b;
113         setAllHandlers();
114     }
115
116     public boolean isDisableDigest() {
117         return disableDigest;
118     }
119
120    
121     /**
122      * Generates a list of http authentication challenges, one for each
123      * supported authentication method, to be sent to the client.
124      *
125      * @param resource - the resoruce being requested
126      * @param request - the current request
127      * @return - a list of http challenges
128      */
129     public List<String> getChallenges( Resource resource, Request request ) {
130         List<String> challenges = new ArrayList<String>();
131         for( AuthenticationHandler h : allHandlers ) {
132             if( h.isCompatible( resource ) ) {
133                 log.debug( "challenge for auth: " + h.getClass() );
134                 String ch = h.getChallenge( resource, request );
135                 challenges.add( ch );
136             } else {
137                 log.debug( "not challenging for auth: " + h.getClass() + " for resource type: " + resource.getClass() );
138             }
139         }
140         return challenges;
141     }
142
143     public List<AuthenticationHandler> getAuthenticationHandlers() {
144         return allHandlers;
145     }
146
147     public List<AuthenticationHandler> getExtraHandlers() {
148         return extraHandlers;
149     }
150
151     public void setExtraHandlers( List<AuthenticationHandler> extraHandlers ) {
152         this.extraHandlers = extraHandlers;
153         setAllHandlers();
154     }
155
156     /**
157      * Merge standard and extra handlers into single list
158      */
159     private void setAllHandlers() {
160         List<AuthenticationHandler> handlers = new ArrayList<AuthenticationHandler>();
161         if( authenticationHandlers != null ) {
162             handlers.addAll( authenticationHandlers );
163         }
164         if( extraHandlers != null ) {
165             handlers.addAll( extraHandlers );
166         }
167         this.allHandlers = Collections.unmodifiableList( handlers );
168     }
169
170     
171         public AuthStatus authenticate( Resource resource, Request request ) {
172         log.trace( "authenticate" );
173         Auth auth = request.getAuthorization();
174         boolean preAuthenticated = ( auth != null && auth.getTag() != null );
175         if( preAuthenticated ) {
176             log.trace( "request is pre-authenticated" );
177             return new AuthStatus( auth, false );
178         }
179         for( AuthenticationHandler h : getAuthenticationHandlers() ) {
180             if( h.supports( resource, request ) ) {
181                 Object loginToken = h.authenticate( resource, request );
182                 if( loginToken == null ) {
183                     log.warn( "authentication failed by AuthenticationHandler:" + h.getClass() );
184                     return new AuthStatus( auth, true );
185                 } else {
186                     if( log.isTraceEnabled() ) {
187                         log.trace( "authentication passed by: " + h.getClass() );
188                     }
189                     if( auth == null ) { // some authentication handlers do not require an Auth object
190                         auth = new Auth( Auth.Scheme.FORM, null, loginToken );
191                         request.setAuthorization( auth );
192                     }
193                     auth.setTag( loginToken );
194                 }
195                 return new AuthStatus( auth, false );
196             }
197         }
198         return null;
199     }
200         
201         /**
202          * A helper method that retrieves a reference to the ExternalAPI bean and
203          * stores it for future use.
204          *
205          * @return an ExternalAPI instance
206          * @throws RpcException in case an error occurs
207          */
208         protected ExternalAPI getService() throws RpcException {
209                 try {
210                         final Context ctx = new InitialContext();
211                         final Object ref = ctx.lookup(getConfiguration().getString("externalApiPath"));
212                         return (ExternalAPI) PortableRemoteObject.narrow(ref, ExternalAPI.class);
213                 } catch (final NamingException e) {
214                         log.error("Unable to retrieve the ExternalAPI EJB", e);
215                         throw new RpcException("An error occurred while contacting the naming service");
216                 }
217         }
218 }