1 package org.apache.maven.archiva.web.rss;
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
12 * http://www.apache.org/licenses/LICENSE-2.0
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
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;
29 import javax.servlet.ServletException;
30 import javax.servlet.http.HttpServlet;
31 import javax.servlet.http.HttpServletRequest;
32 import javax.servlet.http.HttpServletResponse;
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;
55 import com.sun.syndication.feed.synd.SyndFeed;
56 import com.sun.syndication.io.FeedException;
57 import com.sun.syndication.io.SyndFeedOutput;
60 * Servlet for handling rss feed requests.
62 * @author <a href="mailto:oching@apache.org">Maria Odea Ching</a>
65 public class RssFeedServlet
68 public static final String MIME_TYPE = "application/rss+xml; charset=UTF-8";
70 private static final String COULD_NOT_GENERATE_FEED_ERROR = "Could not generate feed";
72 private static final String COULD_NOT_AUTHENTICATE_USER = "Could not authenticate user";
74 private static final String USER_NOT_AUTHORIZED = "User not authorized to access feed.";
76 private Logger log = LoggerFactory.getLogger( RssFeedServlet.class );
78 private RssFeedProcessor processor;
80 private WebApplicationContext wac;
82 private UserRepositories userRepositories;
84 private ServletAuthenticator servletAuth;
86 public void init( javax.servlet.ServletConfig servletConfig )
87 throws ServletException
89 super.init( servletConfig );
90 wac = WebApplicationContextUtils.getRequiredWebApplicationContext( servletConfig.getServletContext() );
92 // (SecuritySystem) wac.getBean( PlexusToSpringUtils.buildSpringId( SecuritySystem.class.getName() ) );
94 (UserRepositories) wac.getBean( PlexusToSpringUtils.buildSpringId( UserRepositories.class.getName() ) );
96 // (HttpAuthenticator) wac.getBean( PlexusToSpringUtils.buildSpringId( HttpAuthenticator.ROLE, "basic" ) );
98 (ServletAuthenticator) wac.getBean( PlexusToSpringUtils.buildSpringId( ServletAuthenticator.class.getName() ) );
101 public void doGet( HttpServletRequest req, HttpServletResponse res )
102 throws ServletException, IOException
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" );
112 if ( ( repoId == null ) && ( groupId == null && artifactId == null ) )
114 res.sendError( HttpServletResponse.SC_BAD_REQUEST, "Required fields not found in request." );
118 if ( isAllowed( req ) )
120 if ( repoId != null )
122 // new artifacts in repo feed request
124 (RssFeedProcessor) wac.getBean( PlexusToSpringUtils.buildSpringId(
125 RssFeedProcessor.class.getName(),
127 map.put( RssFeedProcessor.KEY_REPO_ID, repoId );
129 else if ( ( groupId != null ) && ( artifactId != null ) )
131 // new versions of artifact feed request
133 (RssFeedProcessor) wac.getBean( PlexusToSpringUtils.buildSpringId(
134 RssFeedProcessor.class.getName(),
136 map.put( RssFeedProcessor.KEY_GROUP_ID, groupId );
137 map.put( RssFeedProcessor.KEY_ARTIFACT_ID, artifactId );
142 res.sendError( HttpServletResponse.SC_UNAUTHORIZED, USER_NOT_AUTHORIZED );
146 feed = processor.process( map );
147 res.setContentType( MIME_TYPE );
149 if ( repoId != null )
151 feed.setLink( req.getRequestURL() + "?repoId=" + repoId );
153 else if ( ( groupId != null ) && ( artifactId != null ) )
155 feed.setLink( req.getRequestURL() + "?groupId=" + groupId + "&artifactId=" + artifactId );
158 SyndFeedOutput output = new SyndFeedOutput();
159 output.output( feed, res.getWriter() );
161 catch ( UserNotFoundException unfe )
163 log.error( COULD_NOT_AUTHENTICATE_USER, unfe );
164 res.sendError( HttpServletResponse.SC_UNAUTHORIZED, COULD_NOT_AUTHENTICATE_USER );
166 catch ( AccountLockedException acce )
168 log.error( COULD_NOT_AUTHENTICATE_USER, acce );
169 res.sendError( HttpServletResponse.SC_UNAUTHORIZED, COULD_NOT_AUTHENTICATE_USER );
171 catch ( AuthenticationException authe )
173 log.error( COULD_NOT_AUTHENTICATE_USER, authe );
174 res.sendError( HttpServletResponse.SC_UNAUTHORIZED, COULD_NOT_AUTHENTICATE_USER );
176 catch ( FeedException ex )
178 log.error( COULD_NOT_GENERATE_FEED_ERROR, ex );
179 res.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, COULD_NOT_GENERATE_FEED_ERROR );
181 catch ( MustChangePasswordException e )
183 log.error( COULD_NOT_AUTHENTICATE_USER, e );
184 res.sendError( HttpServletResponse.SC_UNAUTHORIZED, COULD_NOT_AUTHENTICATE_USER );
189 * Basic authentication.
194 private boolean isAllowed( HttpServletRequest req )
195 throws UserNotFoundException, AccountLockedException, AuthenticationException, MustChangePasswordException
197 String auth = req.getHeader( "Authorization" );
198 List<String> repoIds = new ArrayList<String>();
200 if ( req.getParameter( "repoId" ) != null )
202 repoIds.add( req.getParameter( "repoId" ) );
204 else if ( req.getParameter( "artifactId" ) != null && req.getParameter( "version" ) != null )
208 if ( !auth.toUpperCase().startsWith( "BASIC " ) )
213 Decoder dec = new Base64();
214 String usernamePassword = "";
218 usernamePassword = new String( (byte[]) dec.decode( auth.substring( 6 ).getBytes() ) );
220 catch ( DecoderException ie )
222 log.error( "Error decoding username and password.", ie.getMessage() );
225 if ( usernamePassword == null || usernamePassword.trim().equals( "" ) )
227 repoIds = getObservableRepos( ArchivaRoleConstants.PRINCIPAL_GUEST );
231 String[] userCredentials = usernamePassword.split( ":" );
232 repoIds = getObservableRepos( userCredentials[0] );
237 repoIds = getObservableRepos( ArchivaRoleConstants.PRINCIPAL_GUEST );
245 for ( String repoId : repoIds )
249 if ( servletAuth.isAuthenticated( req, repoId ) && servletAuth.isAuthorized( req, repoId, false ) )
254 catch ( AuthorizationException e )
256 log.error( "Fatal Authorization Subsystem Error." );
263 private List<String> getObservableRepos( String principal )
267 return userRepositories.getObservableRepositoryIds( principal );
269 catch ( PrincipalNotFoundException e )
271 log.warn( e.getMessage(), e );
273 catch ( AccessDeniedException e )
275 log.warn( e.getMessage(), e );
277 catch ( ArchivaSecurityException e )
279 log.warn( e.getMessage(), e );
282 return Collections.emptyList();
286 private boolean isAuthenticated( HttpServletRequest request, String repositoryId )
290 AuthenticationResult result = httpAuth.getAuthenticationResult( request, null );
292 if ( result != null && !result.isAuthenticated() )
294 log.error( "User credentials is invalid." );
298 catch ( AuthenticationException e )
300 log.error( "User is not authenticated." );
303 catch ( AccountLockedException e )
305 log.error( "User account is locked." );
308 catch ( MustChangePasswordException e )
310 log.error( "Password must be changed." );
317 private boolean isAuthorized( HttpServletRequest request, String repositoryId )
319 SecuritySession securitySession = httpAuth.getSecuritySession();
323 String permission = ArchivaRoleConstants.OPERATION_REPOSITORY_ACCESS;
325 AuthorizationResult authzResult = securitySystem.authorize( securitySession, permission, repositoryId );
327 if ( !authzResult.isAuthorized() )
329 if ( authzResult.getException() != null )
331 log.info( "Authorization Denied [ip=" + request.getRemoteAddr() + ",permission=" + permission +
332 ",repo=" + repositoryId + "] : " + authzResult.getException().getMessage() );
337 catch ( AuthorizationException e )
339 log.error( "Error in authorization : " + e.getMessage() );