/**********************************************************************************
* $URL: https://source.sakaiproject.org/svn/podcasts/trunk/podcasts/src/java/org/sakaiproject/tool/podcasts/RSSPodfeedServlet.java $
* $Id: RSSPodfeedServlet.java 105079 2012-02-24 23:08:11Z ottenhoff@longsight.com $
***********************************************************************************
*
* Copyright (c) 2003, 2004, 2005, 2006, 2007, 2008 The Sakai Foundation
*
* Licensed under the Educational Community License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.opensource.org/licenses/ECL-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
**********************************************************************************/
package org.sakaiproject.tool.podcasts;
import java.io.IOException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.commons.codec.binary.Base64;
import org.sakaiproject.api.app.podcasts.PodfeedService;
import org.sakaiproject.component.cover.ComponentManager;
import org.sakaiproject.content.cover.ContentHostingService;
import org.sakaiproject.event.api.Event;
import org.sakaiproject.event.cover.EventTrackingService;
import org.sakaiproject.event.cover.NotificationService;
import org.sakaiproject.event.cover.UsageSessionService;
import org.sakaiproject.user.api.Authentication;
import org.sakaiproject.user.api.Evidence;
import org.sakaiproject.user.cover.AuthenticationManager;
import org.sakaiproject.util.IdPwEvidence;
public class RSSPodfeedServlet extends HttpServlet {
/** Used to set the MIME type of the response back to the client **/
private static final String RESPONSE_MIME_TYPE = "application/xml; charset=UTF-8";
/** Used to track the event of generating a public feed **/
private final String EVENT_PUBLIC_FEED = "podcast.read.public";
/** Used to track the event of generating a private feed **/
private final String EVENT_PRIVATE_FEED = "podcast.read.site";
/** FUTURE DEVELOPMENT: set to pass in feed type as a parameter with name 'type' **/
private static final String FEED_TYPE = "type";
private PodfeedService podfeedService;
private final Log LOG = LogFactory.getLog(RSSPodfeedServlet.class);
/**
* The doGet method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to get.
*
* @param request
* the request send by the client to the server
* @param response
* the response send by the server to the client
* @throws ServletException
* if an error occurred
* @throws IOException
* if an error occurred
*/
public void doGet(final HttpServletRequest request,
final HttpServletResponse response) throws ServletException,
IOException {
// get requested URL in attempt to extract siteId
String reqURL = request.getPathInfo();
String siteId;
if (reqURL != null) {
siteId = reqURL.substring(reqURL.lastIndexOf("/") + 1);
}
else {
// could not get it from request URL, try URI
reqURL = request.getRequestURI();
siteId = reqURL.substring(1, reqURL.lastIndexOf("/"));
}
LOG.debug("Podcast feed requested for site: " + siteId);
// get podcast folder id to determine if public/private
final String podcastsCollection = podfeedService.retrievePodcastFolderId(siteId);
// if error finding podcast folder id, will return null, so return
// Internal Server Error message back to client
if (podcastsCollection == null) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
return;
}
// Determine if resource if public/private ("default" - public)
final boolean pubView = ContentHostingService
.isPubView(podcastsCollection);
if (!pubView) {
// if private, was username/password sent with request?
final Evidence e = getBasicAuthEvidence(request);
if ((e != null)) {
// authenticate
try {
LOG.info("Authenticating " + e);
final Authentication a = AuthenticationManager
.authenticate(e);
if (!UsageSessionService.login(a, request)) {
// login failed, so ask for auth again
sendErrorResponse(response);
return;
}
}
catch (final Exception exc) {
// something went wrong, so ask for auth again
sendErrorResponse(response);
return;
}
}
else {
// user name missing, so can't authenticate, so ask for auth
sendErrorResponse(response);
return;
}
// Authenticated, but are they members of the site
// accomplished by doing a check on read access to podcast folder
if (!podfeedService.allowAccess(podcastsCollection)) {
// check to access denied error
response.sendError(403);
}
}
response.setContentType(RESPONSE_MIME_TYPE);
// generates actual feed, 2nd parameter for future to allow different
// feed types currently only rss_2.0 is generated
final String podcastFeed = podfeedService.generatePodcastRSS(siteId,
request.getParameter(FEED_TYPE));
// if problem getting feed, null will be returned so return
// Internal Server Error to client
if (podcastFeed == null || podcastFeed.equals("")) {
response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
}
else {
response.getWriter().write(podcastFeed);
// add entry for event tracking
Event event = null;
if (pubView) {
event = EventTrackingService.newEvent(EVENT_PUBLIC_FEED, podcastsCollection, false, NotificationService.NOTI_NONE);
}
else {
event = EventTrackingService.newEvent(EVENT_PRIVATE_FEED, podcastsCollection, false, NotificationService.NOTI_NONE);
}
EventTrackingService.post(event);
}
}
/**
* The doPost method of the servlet. <br>
*
* This method is called when a form has its tag value method equals to
* post.
*
* @param request
* the request send by the client to the server
* @param response
* the response send by the server to the client
* @throws ServletException
* if an error occurred
* @throws IOException
* if an error occurred
*/
public void doPost(final HttpServletRequest request,
final HttpServletResponse response) throws ServletException,
IOException {
doGet(request, response);
}
/**
* Initialization of the servlet. <br>
*
* @throws ServletException
* if an error occure
*/
public void init() throws ServletException {
LOG.debug(this + ": RSSPodfeedServlet.init()");
podfeedService = (PodfeedService) ComponentManager
.get("org.sakaiproject.api.app.podcasts.PodfeedService");
if (podfeedService == null)
throw new ServletException(new IllegalStateException(
"podfeedService == null"));
}
/**
* @param podfeedService
* The podfeedService to set.
*/
public void setPodfeedService(final PodfeedService podfeedService) {
this.podfeedService = podfeedService;
}
/**
* Extracts auth information if it exists in the HTTP headers
*
* @param request
* The HttpRequest object to be searched
*
* @return IdPwEvidence
* Contains the auth information if found in request headers or null if not found
*/
private IdPwEvidence getBasicAuthEvidence(final HttpServletRequest request) {
Base64 base64Encoder = new Base64();
final String header = request.getHeader("Authorization");
String[] elements = null;
LOG.debug("Authorization: " + header);
if (header != null)
elements = header.split(" ");
if (elements != null && elements.length >= 2) {
final String type = elements[0];
final String hash = elements[1];
LOG.debug("type: " + type + " hash: " + hash);
final String[] credential = (new String(base64Encoder.decode(hash.getBytes())))
.split(":");
LOG.debug("credential: " + credential);
if (credential != null && credential.length >= 2) {
final String eid = credential[0];
final String password = credential[1];
LOG.debug("eid: " + eid + " password: ********");
if ((eid.length() == 0) || (password.length() == 0)) {
return null;
}
return new IdPwEvidence(eid, password);
}
}
return null;
}
/**
* If missing or invalid username/password given, return HTTP 401 to request
* authentication.
*
* @param response
* The Response object so we can set headers
*
* @throws IOException
* Throw this exception back if there was a problem setting the headers
*/
private void sendErrorResponse(final HttpServletResponse response) throws IOException {
response.setHeader("WWW-Authenticate",
HttpServletRequest.BASIC_AUTH
+ " realm=\"Podcaster\"");
response.sendError(401);
}
}