224 lines
8.1 KiB
Java
224 lines
8.1 KiB
Java
package org.gcube.common.authorizationservice.filters;
|
|
|
|
|
|
import java.io.IOException;
|
|
import java.util.List;
|
|
|
|
import javax.inject.Inject;
|
|
import javax.servlet.Filter;
|
|
import javax.servlet.FilterChain;
|
|
import javax.servlet.FilterConfig;
|
|
import javax.servlet.ServletException;
|
|
import javax.servlet.ServletRequest;
|
|
import javax.servlet.ServletResponse;
|
|
import javax.servlet.annotation.WebFilter;
|
|
import javax.servlet.http.HttpServletRequest;
|
|
import javax.servlet.http.HttpServletResponse;
|
|
|
|
import org.gcube.accounting.datamodel.UsageRecord.OperationResult;
|
|
import org.gcube.accounting.datamodel.usagerecords.ServiceUsageRecord;
|
|
import org.gcube.accounting.persistence.AccountingPersistence;
|
|
import org.gcube.accounting.persistence.AccountingPersistenceFactory;
|
|
import org.gcube.common.authorization.library.AuthorizationEntry;
|
|
import org.gcube.common.authorization.library.provider.CalledMethodProvider;
|
|
import org.gcube.common.authorizationservice.configuration.AllowedEntity;
|
|
import org.gcube.common.authorizationservice.configuration.AuthorizationConfiguration;
|
|
import org.gcube.common.authorizationservice.configuration.AuthorizationRule;
|
|
import org.gcube.common.authorizationservice.configuration.ConfigurationHolder;
|
|
import org.gcube.common.authorizationservice.util.TokenPersistence;
|
|
import org.gcube.common.scope.api.ScopeProvider;
|
|
|
|
import lombok.extern.slf4j.Slf4j;
|
|
|
|
@WebFilter(urlPatterns={"/*"}, filterName="authorizationFilter")
|
|
@Slf4j
|
|
public class AuthorizedCallFilter implements Filter {
|
|
|
|
private static final String TOKEN_HEADER="gcube-token";
|
|
|
|
public static final String AUTH_ATTRIBUTE="authorizationInfo";
|
|
|
|
@Inject
|
|
TokenPersistence persistence;
|
|
|
|
@Override
|
|
public void init(FilterConfig filterConfig) throws ServletException {
|
|
|
|
}
|
|
|
|
@Override
|
|
public void doFilter(ServletRequest request, ServletResponse response,
|
|
FilterChain chain) throws IOException, ServletException {
|
|
|
|
|
|
String token = request.getParameter(TOKEN_HEADER)==null?((HttpServletRequest)request).getHeader(TOKEN_HEADER):
|
|
request.getParameter(TOKEN_HEADER);
|
|
|
|
long startTime = System.currentTimeMillis();
|
|
|
|
String callerIp = ((HttpServletRequest)request).getHeader("x-forwarded-for");
|
|
if(callerIp==null)
|
|
callerIp=request.getRemoteHost();
|
|
log.info("caller ip {}", callerIp);
|
|
|
|
AuthorizationEntry info = null;
|
|
if (token!=null){
|
|
info = persistence.getAuthorizationEntry(token);
|
|
log.info("call from {} ",info);
|
|
} else log.info("call without token");
|
|
|
|
request.setAttribute(AUTH_ATTRIBUTE, info);
|
|
|
|
|
|
|
|
String pathInfo = ((HttpServletRequest) request).getPathInfo();
|
|
String servletPath = ((HttpServletRequest) request).getServletPath();
|
|
|
|
|
|
|
|
if (pathInfo==null || pathInfo.isEmpty()){
|
|
|
|
pathInfo = servletPath.replace("/gcube/service", "");
|
|
log.info("called path info {} ", pathInfo);
|
|
if (pathInfo==null || pathInfo.isEmpty()){
|
|
((HttpServletResponse)response).sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
|
|
log.error("call rejected from filters: invalid path");
|
|
generateAccounting("Unknown", "Unknown", callerIp, false, startTime, request.getLocalName());
|
|
return;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
if (requiresToken(pathInfo) && token==null ){
|
|
((HttpServletResponse)response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
|
|
log.error("call rejected from filters, call requires caller token");
|
|
generateAccounting("Unknown", "Unknown", callerIp, false, startTime, request.getLocalName());
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
/*X509Certificate certs[] =
|
|
(X509Certificate[])req.getAttribute("javax.servlet.request.X509Certificate");
|
|
// ... Test if non-null, non-empty.
|
|
|
|
X509Certificate clientCert = certs[0];
|
|
|
|
// Get the Subject DN's X500Principal
|
|
X500Principal subjectDN = clientCert.getSubjectX500Principal();*/
|
|
|
|
if (!checkAllowed(pathInfo, callerIp, info)){
|
|
((HttpServletResponse)response).sendError(HttpServletResponse.SC_UNAUTHORIZED);
|
|
log.error("call rejected from filters");
|
|
generateAccounting("Unknown", "Unknown", callerIp, false, startTime, request.getLocalName());
|
|
return;
|
|
}
|
|
|
|
chain.doFilter(request, response);
|
|
|
|
generateAccounting("Unknown", "Unknown", callerIp, true, startTime, request.getLocalName());
|
|
|
|
}
|
|
|
|
private boolean requiresToken(String pathInfo) {
|
|
AuthorizationConfiguration conf = ConfigurationHolder.getConfiguration();
|
|
List<AuthorizationRule> rules = conf.getAuthorizationRules();
|
|
for (AuthorizationRule rule: rules)
|
|
if (pathInfo.startsWith(rule.getServletPath()) || pathInfo.equals(rule.getServletPath()))
|
|
return rule.isTokenRequired();
|
|
return false;
|
|
}
|
|
|
|
|
|
//TODO: review it, something is not working check if is correct that they are in OR
|
|
private boolean checkAllowed(String pathInfo, String callerIp, AuthorizationEntry info){
|
|
AuthorizationConfiguration conf = ConfigurationHolder.getConfiguration();
|
|
List<AuthorizationRule> rules = conf.getAuthorizationRules();
|
|
for (AuthorizationRule rule: rules){
|
|
if (pathInfo.startsWith(rule.getServletPath()) || pathInfo.equals(rule.getServletPath())){
|
|
if (!rule.getAcceptedTokenType().isEmpty() && !rule.getAcceptedTokenType().contains(info.getClientInfo().getType())){
|
|
log.info("rejecting the call: callerType {} is not in the allowed types defined {} ", info.getClientInfo().getType(), rule.getAcceptedTokenType());
|
|
return false;
|
|
}
|
|
|
|
if (!rule.getEntities().isEmpty()){
|
|
for (AllowedEntity entity : rule.getEntities()){
|
|
switch(entity.getType()){
|
|
case IP:
|
|
log.trace("checking ip rule : {} -> {}", entity.getValue(), callerIp);
|
|
if(checkIpInRange(callerIp, entity.getValue()))
|
|
return true;
|
|
break;
|
|
case USER:
|
|
log.trace("checking user rule : {} -> {}", entity.getValue(), info.getClientInfo().getId());
|
|
if (entity.getValue().equals(info.getClientInfo().getId()))
|
|
return true;
|
|
break;
|
|
case ROLE:
|
|
log.trace("checking role rule : {} -> {}", entity.getValue(), info.getClientInfo().getRoles());
|
|
if (info.getClientInfo().getRoles().contains(entity.getValue()))
|
|
return true;
|
|
break;
|
|
}
|
|
}
|
|
//IF a servlet path matches the caller is not allowed to that servlet (the call should be rejected)
|
|
return false;
|
|
}
|
|
}
|
|
}
|
|
return true;
|
|
}
|
|
|
|
|
|
private static boolean checkIpInRange(String ip, String mask) {
|
|
|
|
String[] maskArray = mask.split("\\.");
|
|
String[] ipArray = ip.split("\\.");
|
|
|
|
int[] maskByte= new int[4];
|
|
int[] ipByte = new int[4];
|
|
|
|
for (int i=0; i<4; i++){
|
|
maskByte[i] = ((Integer)Integer.parseInt(maskArray[i])).byteValue();
|
|
ipByte[i] = ((Integer)Integer.parseInt(ipArray[i])).byteValue();
|
|
}
|
|
return (maskByte[0]==0 || maskByte[0]==ipByte[0]) && (maskByte[1]==0 || maskByte[1]==ipByte[1]) &&
|
|
(maskByte[2]==0 || maskByte[2]==ipByte[2]) && (maskByte[3]==0 || maskByte[3]==ipByte[3]);
|
|
|
|
}
|
|
|
|
|
|
@Override
|
|
public void destroy() {}
|
|
|
|
void generateAccounting(String caller, String callerQualifier, String remoteHost, boolean success, long startTime, String host){
|
|
/*AuthorizationConfiguration conf = ConfigurationHolder.getConfiguration();
|
|
AccountingPersistenceFactory.setFallbackLocation(conf.getAccountingDir());
|
|
AccountingPersistence persistence = AccountingPersistenceFactory.getPersistence();
|
|
ServiceUsageRecord serviceUsageRecord = new ServiceUsageRecord();
|
|
try{
|
|
|
|
serviceUsageRecord.setConsumerId(caller);
|
|
serviceUsageRecord.setCallerQualifier(callerQualifier);
|
|
serviceUsageRecord.setScope(ScopeProvider.instance.get());
|
|
serviceUsageRecord.setServiceClass("Common");
|
|
serviceUsageRecord.setServiceName("Authorization");
|
|
|
|
serviceUsageRecord.setHost(host);
|
|
serviceUsageRecord.setCalledMethod(CalledMethodProvider.instance.get());
|
|
serviceUsageRecord.setCallerHost(remoteHost);
|
|
serviceUsageRecord.setOperationResult(success?OperationResult.SUCCESS:OperationResult.FAILED);
|
|
serviceUsageRecord.setDuration(System.currentTimeMillis()-startTime);
|
|
persistence.account(serviceUsageRecord);
|
|
|
|
}catch(Exception ex){
|
|
log.warn("invalid record passed to accounting ",ex);
|
|
}
|
|
*/
|
|
log.info("REQUEST SERVED for method {} in {} ms with result {}", CalledMethodProvider.instance.get(), System.currentTimeMillis()-startTime, success?OperationResult.SUCCESS:OperationResult.FAILED);
|
|
}
|
|
|
|
}
|