/**
* Copyright (c) Istituto Nazionale di Fisica Nucleare (INFN). 2006-2016
*
* Licensed under the Apache 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.apache.org/licenses/LICENSE-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.italiangrid.voms.aa.x509;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.concurrent.TimeUnit;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.commons.lang.StringUtils;
import org.glite.security.voms.admin.configuration.VOMSConfiguration;
import org.glite.security.voms.admin.configuration.VOMSConfigurationConstants;
import org.glite.security.voms.admin.operations.CurrentAdmin;
import org.italiangrid.utils.voms.CurrentSecurityContext;
import org.italiangrid.utils.voms.SecurityContextImpl;
import org.italiangrid.utils.voms.VOMSSecurityContext;
import org.italiangrid.voms.aa.AttributeAuthority;
import org.italiangrid.voms.aa.AttributeAuthorityFactory;
import org.italiangrid.voms.aa.RequestContext;
import org.italiangrid.voms.aa.RequestContextFactory;
import org.italiangrid.voms.aa.VOMSError;
import org.italiangrid.voms.aa.VOMSErrorMessage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class ACServlet extends HttpServlet {
/**
*
*/
private static final long serialVersionUID = 1L;
public static final String LEGACY_REQUEST_HEADER = "X-VOMS-Legacy";
public static final Logger log = LoggerFactory.getLogger(ACServlet.class);
private VOMSResponseBuilder responseBuilder;
private ACGenerator acGenerator;
private ACRequestLogger acRequestLogger;
/**
*
* @param response
* @param context
*/
protected void addDebugHeaders(HttpServletResponse response,
RequestContext context) {
response.addHeader("X-VOMS-FQANs",
StringUtils.join(context.getResponse().getIssuedFQANs(), ","));
response.addHeader("X-VOMS-GAs",
StringUtils.join(context.getResponse().getIssuedGAs(), ","));
}
protected void doGet(HttpServletRequest request, HttpServletResponse response)
throws ServletException, IOException {
RequestContext context = newRequestContext(request);
boolean isLegacyRequest = isLegacyRequest(request);
prepareResponse(response);
if (!isACEndpointEnabled()) {
VOMSErrorMessage em = VOMSErrorMessage.endpointDisabled();
logFailure(context, em.getMessage());
writeErrorResponse(request, response, em, isLegacyRequest);
return;
}
if (CurrentAdmin.instance().isUnauthenticated()) {
logFailure(context, VOMSError.UnauthenticatedClient.getDefaultMessage());
writeErrorResponse(request, response,
VOMSErrorMessage.unauthenticatedClient(), isLegacyRequest);
return;
}
populateRequest(request, context);
AttributeAuthority aa = newAttributeAuthority();
if (!aa.getAttributes(context)) {
VOMSErrorMessage em = context.getResponse().getErrorMessages().get(0);
logFailure(context, em.getMessage());
writeErrorResponse(request, response, em, isLegacyRequest);
return;
} else {
try {
byte[] acBytes = acGenerator.generateVOMSAC(context);
addDebugHeaders(response, context);
writeResponse(response, acBytes, context);
logSuccess(context);
return;
} catch (Throwable t) {
log.error(
"Error encoding user attribute certificate: " + t.getMessage(), t);
logFailure(context, VOMSError.InternalError.getDefaultMessage());
writeErrorResponse(request, response,
VOMSErrorMessage.internalError(t.getMessage()), isLegacyRequest);
}
}
}
@Override
public void init() throws ServletException {
super.init();
responseBuilder = ResponseBuilderFactory.newResponseBuilder();
acGenerator = ACGeneratorFactory.newACGenerator();
acRequestLogger = ACRequestLoggerFactory.newRequestLogger();
}
/**
*
* @return
*/
protected boolean isACEndpointEnabled() {
return VOMSConfiguration.instance().getBoolean(
VOMSConfigurationConstants.VOMS_AA_X509_ACTIVATE_ENDPOINT, true);
}
/**
*
* @param request
* @return
*/
protected boolean isLegacyRequest(HttpServletRequest request) {
return request.getHeader(LEGACY_REQUEST_HEADER) != null;
}
/**
*
* @param context
* @param errorMessage
*/
public void logFailure(RequestContext context, String errorMessage) {
acRequestLogger.logFailure(context, errorMessage);
}
/**
*
* @param context
*/
public void logSuccess(RequestContext context) {
acRequestLogger.logSuccess(context);
}
/**
*
* @return
*/
protected AttributeAuthority newAttributeAuthority() {
long maximumValidity = VOMSConfiguration.instance().getLong(
VOMSConfigurationConstants.VOMS_AA_X509_MAX_AC_VALIDITY,
TimeUnit.HOURS.toSeconds(12));
boolean legacyFQANEncoding = VOMSConfiguration.instance().getBoolean(
VOMSConfigurationConstants.VOMS_AA_X509_LEGACY_FQAN_ENCODING, true);
return AttributeAuthorityFactory.newAttributeAuthority(maximumValidity,
legacyFQANEncoding);
}
/**
*
* @param request
* @return
*/
protected RequestContext newRequestContext(HttpServletRequest request) {
RequestContext context = RequestContextFactory.newContext();
String subject = CurrentAdmin.instance().getRealSubject();
String issuer = CurrentAdmin.instance().getRealIssuer();
context.getRequest().setRequesterSubject(subject);
context.getRequest().setRequesterIssuer(issuer);
context.getRequest().setHolderSubject(subject);
context.getRequest().setHolderIssuer(issuer);
context.setVOName(VOMSConfiguration.instance().getVOName());
context.setHost(VOMSConfiguration.instance().getHostname());
context.setPort(request.getServerPort());
return context;
}
/**
*
* @param request
* @return
*/
protected List<String> parseRequestedFQANs(HttpServletRequest request) {
String fqansString = request.getParameter("fqans");
if (fqansString == null)
return Collections.emptyList();
List<String> requestedFQANs = new ArrayList<String>();
if (fqansString.contains(",")) {
for (String s : StringUtils.split(fqansString, ","))
requestedFQANs.add(s);
} else
requestedFQANs.add(fqansString);
return requestedFQANs;
}
/**
*
* @param request
* @return
*/
private List<String> parseTargetsFromRequest(HttpServletRequest request) {
String targets = request.getParameter("targets");
if (targets == null)
return Collections.emptyList();
List<String> targetList = new ArrayList<String>();
if (targets.contains(",")) {
String targetTokens[] = targets.split(",");
for (String t : targetTokens)
targetList.add(t);
} else {
targetList = Collections.singletonList(targets);
}
return targetList;
}
/**
* Parse
*
* @param request
* @return
*/
private long parseValidityFromRequest(HttpServletRequest request) {
long lifetime = -1;
try {
String lifetimeString = request.getParameter("lifetime");
if (lifetimeString != null)
lifetime = Long.parseLong(request.getParameter("lifetime"));
} catch (NumberFormatException e) {
// Ignore strange things in lifetime parameter
}
return lifetime;
}
/**
*
* @param request
* @param context
*/
private void populateRequest(HttpServletRequest request,
RequestContext context) {
VOMSSecurityContext ctxt = (VOMSSecurityContext) CurrentSecurityContext
.get();
context.getRequest().setHolderCert(ctxt.getClientCert());
context.getRequest().setRequestedFQANs(parseRequestedFQANs(request));
context.getRequest()
.setRequestedValidity(parseValidityFromRequest(request));
context.getRequest().setTargets(parseTargetsFromRequest(request));
context.getRequest().setOwnedAttributes(ctxt.getVOMSAttributes());
}
/**
*
* @param response
*/
protected void prepareResponse(HttpServletResponse response) {
response.setContentType("text/xml");
response.setCharacterEncoding("UTF-8");
}
/**
*
* @param request
* @param response
* @param errorMessage
* @param isLegacyClient
* @throws ServletException
* @throws IOException
*/
protected void writeErrorResponse(HttpServletRequest request,
HttpServletResponse response, VOMSErrorMessage errorMessage,
boolean isLegacyClient) throws ServletException, IOException {
response.setStatus(errorMessage.getError().getHttpStatus());
String responseString = null;
if (isLegacyClient) {
responseString = responseBuilder.createLegacyErrorResponse(errorMessage);
} else
responseString = responseBuilder.createErrorResponse(errorMessage);
response.getOutputStream().write(responseString.getBytes());
}
/**
*
* @param response
* @param ac
* @param context
* @throws ServletException
* @throws IOException
*/
protected void writeResponse(HttpServletResponse response, byte[] ac,
RequestContext context) throws ServletException, IOException {
String responseString = responseBuilder.createResponse(ac, context
.getResponse().getWarnings());
response.getOutputStream().write(responseString.getBytes());
}
}