/* The contents of this file are subject to the license and copyright terms
* detailed in the license directory at the root of the source tree (also
* available online at http://fedora-commons.org/license/).
*/
package org.fcrepo.server;
import java.net.URI;
import java.util.Arrays;
import java.util.Date;
import java.util.Enumeration;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import javax.servlet.http.HttpServletRequest;
import org.apache.cxf.transport.http.AbstractHTTPDestination;
import org.fcrepo.common.Constants;
import org.fcrepo.server.security.servletfilters.ExtendedHttpServletRequest;
import org.fcrepo.utilities.DateUtility;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Context that is read-only.
*
* @author Chris Wilper
* @version $Id$
*/
public class ReadOnlyContext
implements Context {
private static final Logger logger =
LoggerFactory.getLogger(ReadOnlyContext.class);
public static ReadOnlyContext EMPTY =
new ReadOnlyContext(null, null, null, "", true);
static {
EMPTY.setActionAttributes(null);
EMPTY.setResourceAttributes(null);
}
private static final String[] EMPTY_STRING_ARRAY = new String[0];
private final Date now = new Date();
private MultiValueMap<URI> m_environmentAttributes;
@Override
public final MultiValueMap<URI> getEnvironmentAttributes() {
return m_environmentAttributes;
}
private MultiValueMap<String> m_subjectAttributes;
private MultiValueMap<URI> m_actionAttributes;
private MultiValueMap<URI> m_resourceAttributes;
private MultiValueMap<String> m_requestHeaders;
private final String password;
private static final String NOOP_PARAMETER_NAME = "noOp";
public static final boolean NO_OP = true;
public static final boolean DO_OP = false;
public static final String BACKEND_SERVICE = "backendService";
private boolean noOp = false;
private ExtendedHttpServletRequest extendedHttpServletRequest = null;
/**
* Creates and initializes the <code>Context</code>.
*
* @param parameters
* A pre-loaded Map of name-value pairs comprising the context.
*/
private ReadOnlyContext(HttpServletRequest request,
MultiValueMap<URI> environmentAttributes,
MultiValueMap<String> subjectAttributes,
String password,
boolean noOp) {
setEnvironmentValues(environmentAttributes);
m_subjectAttributes = subjectAttributes;
if (m_subjectAttributes == null) {
logger.debug("subject map parm is null");
m_subjectAttributes = new MultiValueMap<String>();
}
m_subjectAttributes.lock();
logger.debug("subject attributes in readonlycontext constructor == {}",
m_subjectAttributes);
m_actionAttributes = new MultiValueMap<URI>();
m_actionAttributes.lock();
m_resourceAttributes = new MultiValueMap<URI>();
m_resourceAttributes.lock();
if (password == null) {
password = "";
}
this.password = password;
this.noOp = noOp;
if (request instanceof ExtendedHttpServletRequest) {
extendedHttpServletRequest = (ExtendedHttpServletRequest) request;
}
m_requestHeaders = getHeaders(request);
}
public void setEnvironmentValues(MultiValueMap<URI> environmentAttributes) {
m_environmentAttributes = environmentAttributes;
if (m_environmentAttributes == null) {
m_environmentAttributes = new MultiValueMap<URI>();
}
m_environmentAttributes.lock();
}
@Override
public Iterator<URI> environmentAttributes() {
return m_environmentAttributes.names();
}
@Override
public int nEnvironmentValues(URI name) {
return m_environmentAttributes.length(name);
}
@Override
public String getEnvironmentValue(URI name) {
return m_environmentAttributes.getString(name);
}
@Override
public String[] getEnvironmentValues(URI name) {
return m_environmentAttributes.getStringArray(name);
}
@Override
public Iterator<String> subjectAttributes() {
return m_subjectAttributes.names();
}
@Override
public int nSubjectValues(String name) {
int n = m_subjectAttributes.length(name);
logger.debug("N SUBJECT VALUES without == {}", n);
if (extendedHttpServletRequest != null
&& extendedHttpServletRequest.isUserInRole(name)) {
n++;
}
logger.debug("N SUBJECT VALUES with == {}", n);
return n;
}
@Override
public String getSubjectValue(String name) {
String value = null;
if (m_subjectAttributes.length(name) == 1) {
value = m_subjectAttributes.getString(name);
logger.debug("SINGLE SUBJECT VALUE from map == {}", value);
} else if (extendedHttpServletRequest != null
&& extendedHttpServletRequest.isUserInRole(name)) {
value = "";
logger.debug("SINGLE SUBJECT VALUE from iuir() == {}", value);
}
return value;
}
@Override
public String[] getSubjectValues(String name) {
int n = m_subjectAttributes.length(name);
if (extendedHttpServletRequest != null
&& extendedHttpServletRequest.isUserInRole(name)) {
n++;
}
if (n == 0) return null;
String[] values = new String[n];
String[] temp = m_subjectAttributes.getStringArray(name);
System.arraycopy(temp, 0, values, 0, temp.length);
if (extendedHttpServletRequest != null
&& extendedHttpServletRequest.isUserInRole(name)) {
values[n - 1] = "";
}
if (logger.isDebugEnabled()) {
StringBuilder sb = new StringBuilder();
sb.append("INNER RETURNING " + values.length + " VALUES FOR "
+ name + " ==");
for (int i = 0; i < values.length; i++) {
sb.append(" " + values[i]);
}
logger.debug(sb.toString());
}
return values;
}
@Override
public void setActionAttributes(MultiValueMap<URI> actionAttributes) {
if (actionAttributes == null) {
m_actionAttributes = new MultiValueMap<URI>();
} else {
m_actionAttributes = actionAttributes;
}
m_actionAttributes.lock();
}
@Override
public Iterator<URI> actionAttributes() {
return m_actionAttributes.names();
}
@Override
public int nActionValues(URI name) {
return m_actionAttributes.length(name);
}
@Override
public String getActionValue(URI name) {
return m_actionAttributes.getString(name);
}
@Override
public String[] getActionValues(URI name) {
return m_actionAttributes.getStringArray(name);
}
@Override
public Iterator<URI> resourceAttributes() {
return m_resourceAttributes.names();
}
@Override
public void setResourceAttributes(MultiValueMap<URI> resourceAttributes) {
if (resourceAttributes == null) {
m_resourceAttributes = new MultiValueMap<URI>();
} else {
m_resourceAttributes = resourceAttributes;
}
m_resourceAttributes.lock();
}
@Override
public int nResourceValues(URI name) {
return m_resourceAttributes.length(name);
}
@Override
public String getResourceValue(URI name) {
return m_resourceAttributes.getString(name);
}
@Override
public String[] getResourceValues(URI name) {
return m_resourceAttributes.getStringArray(name);
}
@Override
public String toString() {
StringBuilder buffer = new StringBuilder(256);
buffer.append("READ-ONLY CONTEXT:\n");
buffer.append(m_environmentAttributes);
buffer.append(m_subjectAttributes);
buffer.append(m_actionAttributes);
buffer.append(m_resourceAttributes);
buffer.append("(END-READ ONLY CONTEXT)\n");
return buffer.toString();
}
@Override
public Date now() {
return now;
}
private static final MultiValueMap<URI> beginEnvironmentMap(String messageProtocol)
throws Exception {
MultiValueMap<URI> environmentMap = new MultiValueMap<URI>();
environmentMap.set(Constants.HTTP_REQUEST.MESSAGE_PROTOCOL.attributeId,
messageProtocol);
Date now = new Date();
environmentMap.set(Constants.ENVIRONMENT.CURRENT_DATE_TIME.attributeId,
DateUtility.convertDateToString(now));
environmentMap.set(Constants.ENVIRONMENT.CURRENT_DATE.attributeId, DateUtility
.convertDateToDateString(now));
environmentMap.set(Constants.ENVIRONMENT.CURRENT_TIME.attributeId, DateUtility
.convertDateToTimeString(now));
return environmentMap;
}
public static Context getSoapContext(javax.xml.ws.handler.MessageContext ctx) {
HttpServletRequest req = (HttpServletRequest) ctx.get(AbstractHTTPDestination.HTTP_REQUEST);
return ReadOnlyContext.getContext(Constants.HTTP_REQUEST.SOAP.uri, req);
}
private static final ReadOnlyContext getContext(HttpServletRequest request,
MultiValueMap<URI> environmentMap,
String subjectId,
String password, /*
* String[]
* roles,
*/
Map<String, ?> auxSubjectRoles,
boolean noOp) {
MultiValueMap<String> subjectMap = new MultiValueMap<String>();
try {
subjectMap.set(Constants.SUBJECT.LOGIN_ID.uri,
subjectId == null ? "" : subjectId);
/*
* for (int i = 0; (roles != null) && (i < roles.length); i++) {
* String[] parts = parseRole(roles[i]); if ((parts != null) &&
* parts.length == 2) { subjectMap.set(parts[0],parts[1]); //todo:
* handle multiple values (ldap) } }
*/
if (auxSubjectRoles == null) {
logger.debug("IN CONTEXT auxSubjectRoles == null");
} else {
logger.debug("IN CONTEXT processing auxSubjectRoles=={}",
auxSubjectRoles);
logger.debug("IN CONTEXT processing auxSubjectRoles.keySet()=={}",
auxSubjectRoles.keySet());
logger.debug("IN CONTEXT processing auxSubjectRoles.keySet().isEmpty()=={}",
auxSubjectRoles.keySet().isEmpty());
Iterator<String> auxSubjectRoleKeys =
auxSubjectRoles.keySet().iterator();
logger.debug("IN CONTEXT processing auxSubjectRoleKeys=={}",
auxSubjectRoleKeys);
while (auxSubjectRoleKeys.hasNext()) {
Object name = auxSubjectRoleKeys.next();
logger.debug("IN CONTEXT name=={}", name);
if (name instanceof String) {
logger.debug("IN CONTEXT name is string=={}", name);
Object value = auxSubjectRoles.get(name);
if (value instanceof String
|| value instanceof String[]) {
logger.debug("IN CONTEXT value is string([])");
if (value instanceof String) {
logger.debug("IN CONTEXT value is string=={}",value);
subjectMap.set((String) name, (String)value);
}
if (value instanceof String[]) {
logger.debug("IN CONTEXT value is string[]");
String [] values = (String[]) value;
if (logger.isDebugEnabled()) {
for (int z = 0; z < values.length; z++) {
logger.debug("IN CONTEXT this value=={}",
values[z]);
}
}
subjectMap.set((String) name, values);
}
} else if (value instanceof Set) {
@SuppressWarnings("unchecked")
Set<String> values = (Set<String>) value;
String temp[] = values.toArray(EMPTY_STRING_ARRAY);
if (logger.isDebugEnabled()) {
for (String singleValue: temp) {
logger.debug("IN CONTEXT singleValue is string=={}",
singleValue);
}
}
subjectMap.set((String)name, temp);
}
}
}
logger.debug("IN CONTEXT after while");
}
} catch (Exception e) {
logger.error("caught exception building subjectMap " + e.getMessage(),
e);
} finally {
subjectMap.lock();
}
return new ReadOnlyContext(request,
environmentMap,
subjectMap,
password == null ? "" : password,
noOp);
}
// needed only for rebuild
public static final ReadOnlyContext getContext(String messageProtocol,
String subjectId,
String password, /*
* String[]
* roles,
*/
boolean noOp)
throws Exception {
MultiValueMap<URI> environmentMap = beginEnvironmentMap(messageProtocol);
environmentMap.lock(); // no request to grok more from
return getContext(null, environmentMap, subjectId, password, /* roles, */
null, noOp);
}
@SuppressWarnings("unchecked")
public static final ReadOnlyContext getContext(String messageProtocol,
HttpServletRequest request /*
* ,
* String[]
* overrideRoles
*/) {
MultiValueMap<URI> environmentMap = null;
try {
environmentMap = beginEnvironmentMap(messageProtocol);
environmentMap.set(Constants.HTTP_REQUEST.SECURITY.attributeId, request
.isSecure() ? Constants.HTTP_REQUEST.SECURE.uri
: Constants.HTTP_REQUEST.INSECURE.uri);
environmentMap.set(Constants.HTTP_REQUEST.SESSION_STATUS.attributeId,
request.isRequestedSessionIdValid() ? "valid"
: "invalid");
String sessionEncoding = null;
if (request.isRequestedSessionIdFromCookie()) {
sessionEncoding = "cookie";
} else if (request.isRequestedSessionIdFromURL()) {
sessionEncoding = "url";
}
if (request.getContextPath() != null){
environmentMap.set(Constants.FEDORA_APP_CONTEXT_NAME, request.getContextPath().replace("/", ""));
}
if (request.getContentLength() > -1) {
environmentMap.set(Constants.HTTP_REQUEST.CONTENT_LENGTH.attributeId,
Integer.toString(request.getContentLength()));
}
if (request.getLocalPort() > -1) {
environmentMap.set(Constants.HTTP_REQUEST.SERVER_PORT.attributeId,
Integer.toString(request.getLocalPort()));
}
if (request.getProtocol() != null) {
environmentMap.set(Constants.HTTP_REQUEST.PROTOCOL.attributeId, request
.getProtocol());
}
if (request.getScheme() != null) {
environmentMap.set(Constants.HTTP_REQUEST.SCHEME.attributeId, request
.getScheme());
}
if (request.getAuthType() != null) {
environmentMap.set(Constants.HTTP_REQUEST.AUTHTYPE.attributeId, request
.getAuthType());
}
if (request.getMethod() != null) {
environmentMap.set(Constants.HTTP_REQUEST.METHOD.attributeId, request
.getMethod());
}
if (sessionEncoding != null) {
environmentMap.set(Constants.HTTP_REQUEST.SESSION_ENCODING.attributeId,
sessionEncoding);
}
if (request.getContentType() != null) {
environmentMap.set(Constants.HTTP_REQUEST.CONTENT_TYPE.attributeId,
request.getContentType());
}
if (request.getLocalAddr() != null) {
logger.debug("Request Server IP Address is '{}'", request.getLocalAddr());
environmentMap
.set(Constants.HTTP_REQUEST.SERVER_IP_ADDRESS.attributeId,
request.getLocalAddr());
}
if (request.getRemoteAddr() != null) {
logger.debug("Request Client IP Address is '{}'", request.getRemoteAddr());
environmentMap
.set(Constants.HTTP_REQUEST.CLIENT_IP_ADDRESS.attributeId,
request.getRemoteAddr());
}
if (request.getRemoteHost() != null) {
if (!request.getRemoteHost()
.matches("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")) {
environmentMap.set(Constants.HTTP_REQUEST.CLIENT_FQDN.attributeId,
request.getRemoteHost().toLowerCase());
}
}
if (request.getLocalName() != null) {
if (!request.getLocalName()
.matches("\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}\\.\\d{1,3}")) {
environmentMap.set(Constants.HTTP_REQUEST.SERVER_FQDN.attributeId,
request.getLocalName().toLowerCase());
}
}
} catch (Exception e) {
} finally {
environmentMap.lock();
}
String subjectId = request.getRemoteUser();
String password = null;
try {
if (request instanceof ExtendedHttpServletRequest){
password = ((ExtendedHttpServletRequest) request).getPassword();
}
} catch (Throwable th) {
logger.error("in context, can't grok password from extended request "
+ th.getMessage());
}
if (subjectId == null) {
subjectId = "";
}
if (password == null) {
password = "";
}
boolean noOp = true; //safest approach
try {
noOp = Boolean.parseBoolean(request.getParameter(NOOP_PARAMETER_NAME));
logger.debug("NOOP_PARAMETER_NAME={}", NOOP_PARAMETER_NAME);
logger.debug("request.getParameter(NOOP_PARAMETER_NAME)={}",
request.getParameter(NOOP_PARAMETER_NAME));
logger.debug("noOp={}", noOp);
} catch (Exception e) {
logger.error(e.getMessage(), e);
}
Map<String, ?> auxSubjectRoles = null;
Object testFedoraAuxSubjectAttributes =
request.getAttribute(FEDORA_AUX_SUBJECT_ATTRIBUTES);
if (testFedoraAuxSubjectAttributes != null
&& testFedoraAuxSubjectAttributes instanceof Map) {
auxSubjectRoles = (Map<String, ?>) testFedoraAuxSubjectAttributes;
}
return getContext(request, environmentMap, subjectId, password,
auxSubjectRoles, noOp);
}
@Override
public String getPassword() {
return password;
}
@Override
public boolean getNoOp() {
return noOp;
}
@Override
public MultiValueMap<String> getHeaders() {
return m_requestHeaders;
}
@Override
public String getHeaderValue(String name) {
return m_requestHeaders.getString(name.toLowerCase());
}
@Override
public String[] getHeaderValues(String name) {
return m_requestHeaders.getStringArray(name.toLowerCase());
}
private static MultiValueMap<String> getHeaders(HttpServletRequest request) {
MultiValueMap<String> result = new MultiValueMap<String>();
if (request == null) return result;
@SuppressWarnings("unchecked")
Enumeration<String> names = request.getHeaderNames();
while(names != null && names.hasMoreElements()) {
String name = names.nextElement().toLowerCase();
@SuppressWarnings("unchecked")
Enumeration<String> values = request.getHeaders(name);
while(values.hasMoreElements()) {
String next = values.nextElement();
if (result.length(name) > 0) {
String[] prev = result.getStringArray(name);
String[]temp = Arrays.copyOf(prev, prev.length + 1);
temp[temp.length - 1] = next;
result.set(name, temp);
} else {
result.set(name, next);
}
}
}
return result;
}
}