]> source.dussan.org Git - archiva.git/blob
d26a2bc600b500a1d73f318a91ce8a9817b129b3
[archiva.git] /
1 package org.apache.maven.archiva.web.rss;
2
3 /*
4  * Licensed to the Apache Software Foundation (ASF) under one
5  * or more contributor license agreements.  See the NOTICE file
6  * distributed with this work for additional information
7  * regarding copyright ownership.  The ASF licenses this file
8  * to you under the Apache License, Version 2.0 (the
9  * "License"); you may not use this file except in compliance
10  * with the License.  You may obtain a copy of the License at
11  *
12  *  http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing,
15  * software distributed under the License is distributed on an
16  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17  * KIND, either express or implied.  See the License for the
18  * specific language governing permissions and limitations
19  * under the License.
20  */
21
22 import java.io.IOException;
23 import java.util.ArrayList;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.List;
27 import java.util.Map;
28
29 import javax.servlet.ServletException;
30 import javax.servlet.http.HttpServlet;
31 import javax.servlet.http.HttpServletRequest;
32 import javax.servlet.http.HttpServletResponse;
33
34 import org.apache.archiva.rss.processor.RssFeedProcessor;
35 import org.apache.commons.codec.Decoder;
36 import org.apache.commons.codec.DecoderException;
37 import org.apache.commons.codec.binary.Base64;
38 import org.apache.maven.archiva.security.AccessDeniedException;
39 import org.apache.maven.archiva.security.ArchivaRoleConstants;
40 import org.apache.maven.archiva.security.ArchivaSecurityException;
41 import org.apache.maven.archiva.security.PrincipalNotFoundException;
42 import org.apache.maven.archiva.security.ServletAuthenticator;
43 import org.apache.maven.archiva.security.UserRepositories;
44 import org.codehaus.plexus.redback.authentication.AuthenticationException;
45 import org.codehaus.plexus.redback.authorization.AuthorizationException;
46 import org.codehaus.plexus.redback.policy.AccountLockedException;
47 import org.codehaus.plexus.redback.policy.MustChangePasswordException;
48 import org.codehaus.plexus.redback.users.UserNotFoundException;
49 import org.codehaus.plexus.spring.PlexusToSpringUtils;
50 import org.slf4j.Logger;
51 import org.slf4j.LoggerFactory;
52 import org.springframework.web.context.WebApplicationContext;
53 import org.springframework.web.context.support.WebApplicationContextUtils;
54
55 import com.sun.syndication.feed.synd.SyndFeed;
56 import com.sun.syndication.io.FeedException;
57 import com.sun.syndication.io.SyndFeedOutput;
58
59 /**
60  * Servlet for handling rss feed requests.
61  * 
62  * @author <a href="mailto:oching@apache.org">Maria Odea Ching</a>
63  * @version
64  */
65 public class RssFeedServlet
66     extends HttpServlet
67 {
68     public static final String MIME_TYPE = "application/rss+xml; charset=UTF-8";
69
70     private static final String COULD_NOT_GENERATE_FEED_ERROR = "Could not generate feed";
71
72     private static final String COULD_NOT_AUTHENTICATE_USER = "Could not authenticate user";
73
74     private static final String USER_NOT_AUTHORIZED = "User not authorized to access feed.";
75
76     private Logger log = LoggerFactory.getLogger( RssFeedServlet.class );
77
78     private RssFeedProcessor processor;
79
80     private WebApplicationContext wac;
81
82     private UserRepositories userRepositories;
83
84     private ServletAuthenticator servletAuth;
85
86     public void init( javax.servlet.ServletConfig servletConfig )
87         throws ServletException
88     {
89         super.init( servletConfig );
90         wac = WebApplicationContextUtils.getRequiredWebApplicationContext( servletConfig.getServletContext() );
91         // securitySystem =
92         // (SecuritySystem) wac.getBean( PlexusToSpringUtils.buildSpringId( SecuritySystem.class.getName() ) );
93         userRepositories =
94             (UserRepositories) wac.getBean( PlexusToSpringUtils.buildSpringId( UserRepositories.class.getName() ) );
95         // httpAuth =
96         // (HttpAuthenticator) wac.getBean( PlexusToSpringUtils.buildSpringId( HttpAuthenticator.ROLE, "basic" ) );
97         servletAuth =
98             (ServletAuthenticator) wac.getBean( PlexusToSpringUtils.buildSpringId( ServletAuthenticator.class.getName() ) );
99     }
100
101     public void doGet( HttpServletRequest req, HttpServletResponse res )
102         throws ServletException, IOException
103     {
104         try
105         {
106             Map<String, String> map = new HashMap<String, String>();
107             SyndFeed feed = null;
108             String repoId = req.getParameter( "repoId" );
109             String groupId = req.getParameter( "groupId" );
110             String artifactId = req.getParameter( "artifactId" );
111
112             if ( ( repoId == null ) && ( groupId == null && artifactId == null ) )
113             {
114                 res.sendError( HttpServletResponse.SC_BAD_REQUEST, "Required fields not found in request." );
115                 return;
116             }
117
118             if ( isAllowed( req ) )
119             {
120                 if ( repoId != null )
121                 {
122                     // new artifacts in repo feed request
123                     processor =
124                         (RssFeedProcessor) wac.getBean( PlexusToSpringUtils.buildSpringId(
125                                                                                            RssFeedProcessor.class.getName(),
126                                                                                            "new-artifacts" ) );
127                     map.put( RssFeedProcessor.KEY_REPO_ID, repoId );
128                 }
129                 else if ( ( groupId != null ) && ( artifactId != null ) )
130                 {
131                     // new versions of artifact feed request
132                     processor =
133                         (RssFeedProcessor) wac.getBean( PlexusToSpringUtils.buildSpringId(
134                                                                                            RssFeedProcessor.class.getName(),
135                                                                                            "new-versions" ) );
136                     map.put( RssFeedProcessor.KEY_GROUP_ID, groupId );
137                     map.put( RssFeedProcessor.KEY_ARTIFACT_ID, artifactId );
138                 }
139             }
140             else
141             {
142                 res.sendError( HttpServletResponse.SC_UNAUTHORIZED, USER_NOT_AUTHORIZED );
143                 return;
144             }
145
146             feed = processor.process( map );
147             res.setContentType( MIME_TYPE );
148
149             if ( repoId != null )
150             {
151                 feed.setLink( req.getRequestURL() + "?repoId=" + repoId );
152             }
153             else if ( ( groupId != null ) && ( artifactId != null ) )
154             {
155                 feed.setLink( req.getRequestURL() + "?groupId=" + groupId + "&artifactId=" + artifactId );
156             }
157
158             SyndFeedOutput output = new SyndFeedOutput();
159             output.output( feed, res.getWriter() );
160         }
161         catch ( UserNotFoundException unfe )
162         {
163             log.error( COULD_NOT_AUTHENTICATE_USER, unfe );
164             res.sendError( HttpServletResponse.SC_UNAUTHORIZED, COULD_NOT_AUTHENTICATE_USER );
165         }
166         catch ( AccountLockedException acce )
167         {
168             log.error( COULD_NOT_AUTHENTICATE_USER, acce );
169             res.sendError( HttpServletResponse.SC_UNAUTHORIZED, COULD_NOT_AUTHENTICATE_USER );
170         }
171         catch ( AuthenticationException authe )
172         {
173             log.error( COULD_NOT_AUTHENTICATE_USER, authe );
174             res.sendError( HttpServletResponse.SC_UNAUTHORIZED, COULD_NOT_AUTHENTICATE_USER );
175         }
176         catch ( FeedException ex )
177         {
178             log.error( COULD_NOT_GENERATE_FEED_ERROR, ex );
179             res.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, COULD_NOT_GENERATE_FEED_ERROR );
180         }
181         catch ( MustChangePasswordException e )
182         {
183             log.error( COULD_NOT_AUTHENTICATE_USER, e );
184             res.sendError( HttpServletResponse.SC_UNAUTHORIZED, COULD_NOT_AUTHENTICATE_USER );
185         }
186     }
187
188     /**
189      * Basic authentication.
190      * 
191      * @param req
192      * @return
193      */
194     private boolean isAllowed( HttpServletRequest req )
195         throws UserNotFoundException, AccountLockedException, AuthenticationException, MustChangePasswordException
196     {
197         String auth = req.getHeader( "Authorization" );
198         List<String> repoIds = new ArrayList<String>();
199
200         if ( req.getParameter( "repoId" ) != null )
201         {
202             repoIds.add( req.getParameter( "repoId" ) );
203         }
204         else if ( req.getParameter( "artifactId" ) != null && req.getParameter( "version" ) != null )
205         {
206             if ( auth != null )
207             {
208                 if ( !auth.toUpperCase().startsWith( "BASIC " ) )
209                 {
210                     return false;
211                 }
212
213                 Decoder dec = new Base64();
214                 String usernamePassword = "";
215
216                 try
217                 {
218                     usernamePassword = new String( (byte[]) dec.decode( auth.substring( 6 ).getBytes() ) );
219                 }
220                 catch ( DecoderException ie )
221                 {
222                     log.error( "Error decoding username and password.", ie.getMessage() );
223                 }
224
225                 if ( usernamePassword == null || usernamePassword.trim().equals( "" ) )
226                 {
227                     repoIds = getObservableRepos( ArchivaRoleConstants.PRINCIPAL_GUEST );
228                 }
229                 else
230                 {
231                     String[] userCredentials = usernamePassword.split( ":" );
232                     repoIds = getObservableRepos( userCredentials[0] );
233                 }
234             }
235             else
236             {
237                 repoIds = getObservableRepos( ArchivaRoleConstants.PRINCIPAL_GUEST );
238             }
239         }
240         else
241         {
242             return false;
243         }
244
245         for ( String repoId : repoIds )
246         {
247             try
248             {
249                 if ( servletAuth.isAuthenticated( req, repoId ) && servletAuth.isAuthorized( req, repoId, false ) )
250                 {
251                     return true;
252                 }
253             }
254             catch ( AuthorizationException e )
255             {
256                 log.error( "Fatal Authorization Subsystem Error." );
257             }
258         }
259
260         return false;
261     }
262
263     private List<String> getObservableRepos( String principal )
264     {
265         try
266         {
267             return userRepositories.getObservableRepositoryIds( principal );
268         }
269         catch ( PrincipalNotFoundException e )
270         {
271             log.warn( e.getMessage(), e );
272         }
273         catch ( AccessDeniedException e )
274         {
275             log.warn( e.getMessage(), e );
276         }
277         catch ( ArchivaSecurityException e )
278         {
279             log.warn( e.getMessage(), e );
280         }
281
282         return Collections.emptyList();
283     }
284
285     /*
286     private boolean isAuthenticated( HttpServletRequest request, String repositoryId )
287     {
288         try
289         {
290             AuthenticationResult result = httpAuth.getAuthenticationResult( request, null );
291
292             if ( result != null && !result.isAuthenticated() )
293             {
294                 log.error( "User credentials is invalid." );
295                 return false;
296             }
297         }
298         catch ( AuthenticationException e )
299         {
300             log.error( "User is not authenticated." );
301             return false;
302         }
303         catch ( AccountLockedException e )
304         {
305             log.error( "User account is locked." );
306             return false;
307         }
308         catch ( MustChangePasswordException e )
309         {
310             log.error( "Password must be changed." );
311             return false;
312         }
313
314         return true;
315     }
316
317     private boolean isAuthorized( HttpServletRequest request, String repositoryId )
318     {
319         SecuritySession securitySession = httpAuth.getSecuritySession();
320
321         try
322         {
323             String permission = ArchivaRoleConstants.OPERATION_REPOSITORY_ACCESS;
324
325             AuthorizationResult authzResult = securitySystem.authorize( securitySession, permission, repositoryId );
326
327             if ( !authzResult.isAuthorized() )
328             {
329                 if ( authzResult.getException() != null )
330                 {
331                     log.info( "Authorization Denied [ip=" + request.getRemoteAddr() + ",permission=" + permission +
332                         ",repo=" + repositoryId + "] : " + authzResult.getException().getMessage() );
333                 }
334                 return false;
335             }
336         }
337         catch ( AuthorizationException e )
338         {
339             log.error( "Error in authorization : " + e.getMessage() );
340             return false;
341         }
342
343         return true;
344     }
345      */
346 }