This project has retired. For details please refer to its
Attic page.
RssFeedServlet xref
1 package org.apache.archiva.web.rss;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import com.sun.syndication.feed.synd.SyndFeed;
23 import com.sun.syndication.io.FeedException;
24 import com.sun.syndication.io.SyndFeedOutput;
25 import org.apache.archiva.metadata.repository.RepositorySession;
26 import org.apache.archiva.metadata.repository.RepositorySessionFactory;
27 import org.apache.archiva.redback.authentication.AuthenticationException;
28 import org.apache.archiva.redback.authentication.AuthenticationResult;
29 import org.apache.archiva.redback.authorization.AuthorizationException;
30 import org.apache.archiva.redback.authorization.UnauthorizedException;
31 import org.apache.archiva.redback.integration.filter.authentication.HttpAuthenticator;
32 import org.apache.archiva.redback.policy.AccountLockedException;
33 import org.apache.archiva.redback.policy.MustChangePasswordException;
34 import org.apache.archiva.redback.system.SecuritySession;
35 import org.apache.archiva.redback.users.UserManager;
36 import org.apache.archiva.redback.users.UserNotFoundException;
37 import org.apache.archiva.rss.processor.RssFeedProcessor;
38 import org.apache.archiva.security.AccessDeniedException;
39 import org.apache.archiva.security.ArchivaSecurityException;
40 import org.apache.archiva.security.PrincipalNotFoundException;
41 import org.apache.archiva.security.ServletAuthenticator;
42 import org.apache.archiva.security.UserRepositories;
43 import org.apache.archiva.security.common.ArchivaRoleConstants;
44 import org.apache.commons.codec.Decoder;
45 import org.apache.commons.codec.DecoderException;
46 import org.apache.commons.codec.binary.Base64;
47 import org.apache.commons.lang.StringUtils;
48 import org.slf4j.Logger;
49 import org.slf4j.LoggerFactory;
50 import org.springframework.web.context.WebApplicationContext;
51 import org.springframework.web.context.support.WebApplicationContextUtils;
52
53 import javax.servlet.ServletConfig;
54 import javax.servlet.ServletException;
55 import javax.servlet.http.HttpServlet;
56 import javax.servlet.http.HttpServletRequest;
57 import javax.servlet.http.HttpServletResponse;
58 import java.io.IOException;
59 import java.util.ArrayList;
60 import java.util.Collections;
61 import java.util.HashMap;
62 import java.util.List;
63 import java.util.Map;
64
65
66
67
68 public class RssFeedServlet
69 extends HttpServlet
70 {
71 public static final String MIME_TYPE = "application/rss+xml; charset=UTF-8";
72
73 private static final String COULD_NOT_GENERATE_FEED_ERROR = "Could not generate feed";
74
75 private static final String COULD_NOT_AUTHENTICATE_USER = "Could not authenticate user";
76
77 private static final String USER_NOT_AUTHORIZED = "User not authorized to access feed.";
78
79 private Logger log = LoggerFactory.getLogger( RssFeedServlet.class );
80
81 private WebApplicationContext wac;
82
83 private UserRepositories userRepositories;
84
85 private ServletAuthenticator servletAuth;
86
87 private HttpAuthenticator httpAuth;
88
89 private RssFeedProcessor newArtifactsprocessor;
90
91 private RssFeedProcessor newVersionsprocessor;
92
93
94
95
96 private RepositorySessionFactory repositorySessionFactory;
97
98 @Override
99 public void init( ServletConfig servletConfig )
100 throws ServletException
101 {
102 super.init( servletConfig );
103 wac = WebApplicationContextUtils.getRequiredWebApplicationContext( servletConfig.getServletContext() );
104 userRepositories = wac.getBean( UserRepositories.class );
105 servletAuth = wac.getBean( ServletAuthenticator.class );
106 httpAuth = wac.getBean( "httpAuthenticator#basic", HttpAuthenticator.class );
107
108 repositorySessionFactory = wac.getBean( "repositorySessionFactory", RepositorySessionFactory.class );
109
110 newArtifactsprocessor = wac.getBean( "rssFeedProcessor#new-artifacts", RssFeedProcessor.class );
111 newVersionsprocessor = wac.getBean( "rssFeedProcessor#new-versions", RssFeedProcessor.class );
112 }
113
114 @Override
115 public void doGet( HttpServletRequest req, HttpServletResponse res )
116 throws ServletException, IOException
117 {
118
119
120 String repoId = null;
121 String groupId = null;
122 String artifactId = null;
123
124 String url = StringUtils.removeEnd( req.getRequestURL().toString(), "/" );
125
126 if ( StringUtils.countMatches( StringUtils.substringAfter( url, "feeds/" ), "/" ) > 0 )
127 {
128 artifactId = StringUtils.substringAfterLast( url, "/" );
129 groupId = StringUtils.substringBeforeLast( StringUtils.substringAfter( url, "feeds/" ), "/" );
130 groupId = StringUtils.replaceChars( groupId, '/', '.' );
131 }
132 else if ( StringUtils.countMatches( StringUtils.substringAfter( url, "feeds/" ), "/" ) == 0 )
133 {
134
135 if ( StringUtils.countMatches( url, "feeds?" ) > 0 )
136 {
137 res.sendError( HttpServletResponse.SC_BAD_REQUEST, "Invalid request url." );
138 return;
139 }
140 repoId = StringUtils.substringAfterLast( url, "/" );
141 }
142 else
143 {
144 res.sendError( HttpServletResponse.SC_BAD_REQUEST, "Invalid request url." );
145 return;
146 }
147
148 RssFeedProcessor processor = null;
149
150 try
151 {
152 Map<String, String> map = new HashMap<>();
153 SyndFeed feed = null;
154
155 if ( isAllowed( req, repoId, groupId, artifactId ) )
156 {
157 if ( repoId != null )
158 {
159
160 processor = newArtifactsprocessor;
161 map.put( RssFeedProcessor.KEY_REPO_ID, repoId );
162 }
163 else if ( ( groupId != null ) && ( artifactId != null ) )
164 {
165
166
167 processor = newVersionsprocessor;
168 map.put( RssFeedProcessor.KEY_GROUP_ID, groupId );
169 map.put( RssFeedProcessor.KEY_ARTIFACT_ID, artifactId );
170 }
171 }
172 else
173 {
174 res.sendError( HttpServletResponse.SC_UNAUTHORIZED, USER_NOT_AUTHORIZED );
175 return;
176 }
177
178 RepositorySession repositorySession = repositorySessionFactory.createSession();
179 try
180 {
181 feed = processor.process( map, repositorySession.getRepository() );
182 }
183 finally
184 {
185 repositorySession.close();
186 }
187 if ( feed == null )
188 {
189 res.sendError( HttpServletResponse.SC_NO_CONTENT, "No information available." );
190 return;
191 }
192
193 res.setContentType( MIME_TYPE );
194
195 if ( repoId != null )
196 {
197 feed.setLink( req.getRequestURL().toString() );
198 }
199 else if ( ( groupId != null ) && ( artifactId != null ) )
200 {
201 feed.setLink( req.getRequestURL().toString() );
202 }
203
204 SyndFeedOutput output = new SyndFeedOutput();
205 output.output( feed, res.getWriter() );
206 }
207 catch ( UserNotFoundException unfe )
208 {
209 log.debug( COULD_NOT_AUTHENTICATE_USER, unfe );
210 res.sendError( HttpServletResponse.SC_UNAUTHORIZED, COULD_NOT_AUTHENTICATE_USER );
211 }
212 catch ( AccountLockedException acce )
213 {
214 res.sendError( HttpServletResponse.SC_UNAUTHORIZED, COULD_NOT_AUTHENTICATE_USER );
215 }
216 catch ( AuthenticationException authe )
217 {
218 log.debug( COULD_NOT_AUTHENTICATE_USER, authe );
219 res.sendError( HttpServletResponse.SC_UNAUTHORIZED, COULD_NOT_AUTHENTICATE_USER );
220 }
221 catch ( FeedException ex )
222 {
223 log.debug( COULD_NOT_GENERATE_FEED_ERROR, ex );
224 res.sendError( HttpServletResponse.SC_INTERNAL_SERVER_ERROR, COULD_NOT_GENERATE_FEED_ERROR );
225 }
226 catch ( MustChangePasswordException e )
227 {
228 res.sendError( HttpServletResponse.SC_UNAUTHORIZED, COULD_NOT_AUTHENTICATE_USER );
229 }
230 catch ( UnauthorizedException e )
231 {
232 log.debug( e.getMessage() );
233 if ( repoId != null )
234 {
235 res.setHeader( "WWW-Authenticate",
236 "Basic realm=\"Repository Archiva Managed " + repoId + " Repository" );
237 }
238 else
239 {
240 res.setHeader( "WWW-Authenticate", "Basic realm=\"Artifact " + groupId + ":" + artifactId );
241 }
242
243 res.sendError( HttpServletResponse.SC_UNAUTHORIZED, USER_NOT_AUTHORIZED );
244 }
245 }
246
247
248
249
250
251
252
253
254
255
256 private boolean isAllowed( HttpServletRequest req, String repositoryId, String groupId, String artifactId )
257 throws UserNotFoundException, AccountLockedException, AuthenticationException, MustChangePasswordException,
258 UnauthorizedException
259 {
260 String auth = req.getHeader( "Authorization" );
261 List<String> repoIds = new ArrayList<>();
262
263 if ( repositoryId != null )
264 {
265 repoIds.add( repositoryId );
266 }
267 else if ( artifactId != null && groupId != null )
268 {
269 if ( auth != null )
270 {
271 if ( !auth.toUpperCase().startsWith( "BASIC " ) )
272 {
273 return false;
274 }
275
276 Decoder dec = new Base64();
277 String usernamePassword = "";
278
279 try
280 {
281 usernamePassword = new String( (byte[]) dec.decode( auth.substring( 6 ).getBytes() ) );
282 }
283 catch ( DecoderException ie )
284 {
285 log.warn( "Error decoding username and password: {}", ie.getMessage() );
286 }
287
288 if ( usernamePassword == null || usernamePassword.trim().equals( "" ) )
289 {
290 repoIds = getObservableRepos( UserManager.GUEST_USERNAME );
291 }
292 else
293 {
294 String[] userCredentials = usernamePassword.split( ":" );
295 repoIds = getObservableRepos( userCredentials[0] );
296 }
297 }
298 else
299 {
300 repoIds = getObservableRepos( UserManager.GUEST_USERNAME );
301 }
302 }
303 else
304 {
305 return false;
306 }
307
308 for ( String repoId : repoIds )
309 {
310 try
311 {
312 AuthenticationResult result = httpAuth.getAuthenticationResult( req, null );
313 SecuritySession securitySession = httpAuth.getSecuritySession( req.getSession( true ) );
314
315 if ( servletAuth.isAuthenticated( req, result )
316 && servletAuth.isAuthorized( req,
317 securitySession,
318 repoId,
319 ArchivaRoleConstants.OPERATION_REPOSITORY_ACCESS ) )
320 {
321 return true;
322 }
323 }
324 catch ( AuthorizationException e )
325 {
326 log.debug( "AuthorizationException for repoId: {}", repoId );
327 }
328 catch ( UnauthorizedException e )
329 {
330 log.debug( "UnauthorizedException for repoId: {}", repoId );
331 }
332 }
333
334 throw new UnauthorizedException( "Access denied." );
335 }
336
337 private List<String> getObservableRepos( String principal )
338 {
339 try
340 {
341 return userRepositories.getObservableRepositoryIds( principal );
342 }
343 catch ( PrincipalNotFoundException e )
344 {
345 log.warn( e.getMessage(), e );
346 }
347 catch ( AccessDeniedException e )
348 {
349 log.warn( e.getMessage(), e );
350 }
351 catch ( ArchivaSecurityException e )
352 {
353 log.warn( e.getMessage(), e );
354 }
355
356 return Collections.emptyList();
357 }
358
359 }