/* * Copyright 2012 buddycloud * * 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 com.buddycloud.mediaserver.web; import java.util.ArrayList; import java.util.List; import java.util.concurrent.ConcurrentMap; import org.restlet.Message; import org.restlet.Request; import org.restlet.Response; import org.restlet.data.ChallengeRequest; import org.restlet.data.ChallengeScheme; import org.restlet.data.MediaType; import org.restlet.data.Status; import org.restlet.engine.header.Header; import org.restlet.representation.EmptyRepresentation; import org.restlet.representation.Representation; import org.restlet.representation.StringRepresentation; import org.restlet.resource.Options; import org.restlet.resource.ServerResource; import org.restlet.util.Series; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.buddycloud.mediaserver.commons.AuthBean; import com.buddycloud.mediaserver.commons.Constants; import com.buddycloud.mediaserver.commons.MediaServerConfiguration; import com.buddycloud.mediaserver.commons.exception.MissingAuthenticationException; import com.buddycloud.mediaserver.commons.exception.UserNotAllowedException; import com.buddycloud.mediaserver.xmpp.AuthVerifier; import com.buddycloud.mediaserver.xmpp.XMPPToolBox; public abstract class MediaServerResource extends ServerResource { private static Logger LOGGER = LoggerFactory.getLogger(MediaServerResource.class); protected static final String HEADERS_KEY = "org.restlet.http.headers"; protected static final String ORIGIN_HEADER = "Origin"; // CORS headers protected static final String CORS_ALLOW_HEADER = "Access-Control-Allow-Headers"; protected static final String CORS_CREDENTIALS_HEADER = "Access-Control-Allow-Credentials"; protected static final String CORS_ORIGIN_HEADER = "Access-Control-Allow-Origin"; protected static final String CORS_MAX_AGE = "Access-Control-Max-Age"; protected static final String CORS_METHODS_HEADER = "Access-Control-Allow-Methods"; protected static final String REQUEST_METHOD_HEADER = "Access-Control-Request-Method"; // Server name protected static final String SERVER_NAME = "buddycloud media server"; @Options public Representation getOptions() { addCORSHeaders(getRequest()); return new EmptyRepresentation(); } public void setServerHeader() { getResponse().getServerInfo().setAgent(SERVER_NAME); } @SuppressWarnings("unchecked") protected Series<Header> getMessageHeaders(Message message) { ConcurrentMap<String, Object> attrs = message.getAttributes(); Series<Header> headers = (Series<Header>) attrs.get(HEADERS_KEY); if (headers == null) { headers = new Series<Header>(Header.class); Series<Header> prev = (Series<Header>) attrs.putIfAbsent(HEADERS_KEY, headers); if (prev != null) { headers = prev; } } return headers; } protected void addCORSHeaders() { addCORSHeaders(null); } protected void addCORSHeaders(Request request) { String origin = null; if (request != null) { Series<Header> messageHeaders = getMessageHeaders(request); Header originHeader = messageHeaders.getFirst(ORIGIN_HEADER); // work around for lower case origin headers if (originHeader == null) { messageHeaders.getFirst(ORIGIN_HEADER.toLowerCase()); } origin = originHeader != null ? originHeader.getValue() : null; } getMessageHeaders(getResponse()).add(CORS_ALLOW_HEADER, "Authorization, " + "Content-Type, X-Requested-With, XMLHttpRequest-specific"); getMessageHeaders(getResponse()).add(CORS_ORIGIN_HEADER, (origin == null ? "*" : origin)); getMessageHeaders(getResponse()).add(CORS_METHODS_HEADER, "GET, POST, PUT, DELETE"); getMessageHeaders(getResponse()).add(CORS_CREDENTIALS_HEADER, "true"); getMessageHeaders(getResponse()).add(CORS_MAX_AGE, "86400" /*one day*/); } protected Representation authenticationResponse() { List<ChallengeRequest> challengeRequests = new ArrayList<ChallengeRequest>(); challengeRequests.add(new ChallengeRequest(ChallengeScheme.HTTP_BASIC, MediaServerApplication.REALM)); StringRepresentation representation = new StringRepresentation("Authentication error.", MediaType.APPLICATION_JSON); Response response = getResponse(); response.setChallengeRequests(challengeRequests); response.setEntity(representation); return response.getEntity(); } protected Representation invalidQuery() { return new StringRepresentation("Invalid query value!", MediaType.APPLICATION_JSON); } protected Representation unexpectedError(Throwable t) { LOGGER.error("Unexpected error: " + t.getLocalizedMessage(), t); setStatus(Status.SERVER_ERROR_INTERNAL); return new StringRepresentation("Unexpected error.", MediaType.APPLICATION_JSON); } protected AuthBean buildAuthBean(Request request) { AuthBean authBean; String authToken = getQueryValue(Constants.AUTH_QUERY); if (authToken != null) { authBean = AuthBean.createAuthBean(authToken); } else { authBean = AuthBean.createAuthBean(request); } return authBean; } protected String getUsedJID(Request request, boolean authenticate) throws UserNotAllowedException, MissingAuthenticationException { AuthBean authBean = buildAuthBean(request); if (authBean == null) { throw new MissingAuthenticationException(); } String endpointProp = MediaServerConfiguration.getInstance().getConfiguration().getProperty( MediaServerConfiguration.HTTP_ENDPOINT); String resourceURL = null; if (endpointProp == null) { resourceURL = request.getResourceRef().getIdentifier(); } else { resourceURL = endpointProp + request.getResourceRef().getPath(); } String userJID = authBean.getUserJID(); if (authenticate) { AuthVerifier authClient = XMPPToolBox.getInstance().getAuthClient(); if (!authClient.verifyRequest(userJID, authBean.getTransactionID(), resourceURL)) { throw new UserNotAllowedException(userJID); } } return userJID; } protected Integer getIntegerQueryValue(String query) { Integer result = null; String queryValue = getQueryValue(query); if (queryValue != null) { try { result = Integer.valueOf(queryValue); } catch (NumberFormatException ignored) {} } return result; } }