/*
* Copyright (C) 2015 Stefano Fornari.
* All Rights Reserved. No use, copying or distribution of this
* work may be made except in accordance with a valid license
* agreement from Stefano Fornari. This notice must be
* included on all copies, modifications and derivatives of this
* work.
*
* STEFANO FORNARI MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY
* OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
* THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
* PURPOSE, OR NON-INFRINGEMENT. STEFANO FORNARI SHALL NOT BE LIABLE FOR ANY
* DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING OR DISTRIBUTING
* THIS SOFTWARE OR ITS DERIVATIVES.
*/
package ste.web.http.handlers;
import java.io.IOException;
import java.security.AccessControlException;
import javax.ws.rs.core.HttpHeaders;
import org.apache.http.HttpException;
import org.apache.http.HttpRequest;
import org.apache.http.HttpResponse;
import org.apache.http.HttpStatus;
import org.apache.http.HttpVersion;
import org.apache.http.protocol.HttpContext;
import org.apache.http.protocol.HttpRequestHandler;
import ste.web.http.HttpSessionContext;
import ste.web.acl.AccessControlList;
import ste.web.acl.MissingCredentialsException;
import ste.web.acl.Authenticator;
import ste.web.acl.InvalidCredentialsException;
import ste.web.acl.User;
import ste.web.http.HttpSession;
/**
*
* @author ste
*/
public class RestrictedResourceHandler implements HttpRequestHandler {
private final HttpRequestHandler handler;
private final AccessControlList acl;
private final Authenticator authenticator;
/**
* Creates a new RestrictedResourceHandler that wraps the given handler and
* checks access to the resource accordingly to the given access control
* list (acl). If acl is null, no authentication/authorization check will
* be performed.
*
* Once handler and acl are given they cannot be changed.
*
* @param handler the handler to wrap - NOT NULL
* @param acl the access control list if not null - MAY BE NULL
* @param authenticator the authenticator to use for authentication (if null
* no authentication is performed) - MY BE NULL
*/
public RestrictedResourceHandler(final HttpRequestHandler handler,
final AccessControlList acl,
final Authenticator authenticator) {
if (handler == null) {
throw new IllegalArgumentException("handler can not be null");
}
this.handler = handler;
this.acl = acl;
this.authenticator = authenticator;
}
public HttpRequestHandler getHandler() {
return handler;
}
public AccessControlList getAcl() {
return acl;
}
public Authenticator getAuthenticator() {
return authenticator;
}
@Override
public void handle(HttpRequest request, HttpResponse response, HttpContext context) throws HttpException, IOException {
HttpSessionContext sessionContext = (HttpSessionContext)context;
try {
HttpSession session = sessionContext.getSession();
User user = (User)sessionContext.getPrincipal();
if ((user != null) || (session.getPrincipal() == null)) {
authenticate(user);
authorize(user);
session.setPrincipal(user);
}
handler.handle(request, response, context);
} catch (MissingCredentialsException x) {
response.setStatusLine(
HttpVersion.HTTP_1_1,
HttpStatus.SC_UNAUTHORIZED,
"resource " + request.getRequestLine().getUri() + " requires authentication"
);
response.addHeader(HttpHeaders.WWW_AUTHENTICATE, authenticator.getMessage());
return;
} catch (InvalidCredentialsException x) {
response.setStatusLine(
HttpVersion.HTTP_1_1,
HttpStatus.SC_UNAUTHORIZED,
"invalid credentials"
);
response.addHeader(HttpHeaders.WWW_AUTHENTICATE, authenticator.getMessage());
return;
} catch (AccessControlException x) {
response.setStatusLine(
HttpVersion.HTTP_1_1,
HttpStatus.SC_FORBIDDEN,
"resource " + request.getRequestLine().getUri() + " requires authorization"
);
return;
}
}
// --------------------------------------------------------- private methods
private void authenticate(final User user) throws SecurityException {
if (authenticator != null) {
authenticator.check(user);
}
}
private void authorize(final User user) throws AccessControlException {
if (acl != null) {
acl.check(user.getPermissions());
}
}
}