/* ====================================================================
*
* Copyright (C) 2015 GeoSolutions S.A.S.
* http://www.geo-solutions.it
*
* GPLv3 + Classpath exception
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.
*
* ====================================================================
*
* This software consists of voluntary contributions made by developers
* of GeoSolutions. For more information on GeoSolutions, please see
* <http://www.geo-solutions.it/>.
*
*/
package it.geosolutions.geostore.services.rest.security;
import java.io.IOException;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpException;
import org.apache.commons.httpclient.HttpMethod;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.GetMethod;
import org.apache.commons.httpclient.params.HttpClientParams;
import org.apache.log4j.Logger;
import org.springframework.security.core.Authentication;
/**
* Token based authentication filter that looks for the token calling an external webservice.
*
* The url of the service needs to be configured. A placeholder in the url will be replaced by
* the actual token.
*
* The result of the web service call will be parsed using given regular expression to:
* - check if the token is valid
* - extract the user name from the result
*
* @author Mauro Bartolomeoli
*
*/
public class WebServiceTokenAuthenticationFilter extends TokenAuthenticationFilter {
private final static Logger LOGGER = Logger.getLogger(WebServiceTokenAuthenticationFilter.class);
private String url;
// compiled user search regex
Pattern searchUserRegex = null;
// connection timeout to the mapper web service (in seconds)
long connectTimeout = 5;
// read timeout to the mapper web service (in seconds)
int readTimeout = 10;
// optional external httpClient for web service connection (used mainly for tests)
private HttpClient httpClient = null;
public WebServiceTokenAuthenticationFilter(String url) {
super();
this.url = url;
}
/**
* Regular expression to extract the username from the
* webservice response.
*
* The first group in the expression will be used for extraction.
*
* @param searchUser
*/
public void setSearchUser(String searchUser) {
searchUserRegex = Pattern.compile(searchUser);
}
public void setConnectTimeout(long connectTimeout) {
this.connectTimeout = connectTimeout;
}
public void setReadTimeout(int readTimeout) {
this.readTimeout = readTimeout;
}
/**
* Configures the HTTPClient implementation to be used to connect to the web service.
*
* @param httpClient
*/
public void setHttpClient(HttpClient httpClient) {
this.httpClient = httpClient;
}
private HttpClient getHttpClient() {
if (httpClient == null) {
httpClient = new HttpClient();
}
return httpClient;
}
@Override
protected Authentication checkToken(String token) {
String webServiceUrl = url.replace("{token}", token);
HttpClient client = getHttpClient();
client.getParams().setParameter(HttpClientParams.CONNECTION_MANAGER_TIMEOUT, connectTimeout * 1000l);
client.getParams().setParameter(HttpClientParams.SO_TIMEOUT, readTimeout * 1000);
HttpMethod method = null;
try {
LOGGER.debug("Issuing request to webservice: " + url);
method = new GetMethod(webServiceUrl);
int statusCode = client.executeMethod(method);
if (statusCode == HttpStatus.SC_OK) {
// get response content as a single string, without new lines
// so that is simpler to apply an extraction regular expression
String response = method.getResponseBodyAsString()
.replace("\r", "").replace("\n", "");
if(response != null) {
if (searchUserRegex == null) {
return createAuthenticationForUser(response, null, "");
} else {
Matcher matcher = searchUserRegex.matcher(response);
if (matcher.find()) {
return createAuthenticationForUser(matcher.group(1), null, response);
} else {
LOGGER.warn("Error in getting username from webservice response cannot find userName in response");
}
}
} else {
LOGGER.error("No response received from webservice: " + url);
}
}
} catch (HttpException e) {
LOGGER.error("Error contacting webservice: " + url, e);
} catch (IOException e) {
LOGGER.error("Error reading data from webservice: " + url, e);
} finally {
if(method != null) {
method.releaseConnection();
}
}
return null;
}
}