2016-10-03 16:22:42 +02:00
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 ;
2019-12-09 18:06:21 +01:00
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 ;
2016-10-03 16:22:42 +02:00
import org.gcube.common.authorization.library.AuthorizationEntry ;
2019-12-09 18:06:21 +01:00
import org.gcube.common.authorization.library.provider.CalledMethodProvider ;
2016-10-03 16:22:42 +02:00
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 ;
2019-12-09 18:06:21 +01:00
import org.gcube.common.scope.api.ScopeProvider ;
import lombok.extern.slf4j.Slf4j ;
2016-10-03 16:22:42 +02:00
@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
2019-12-09 18:06:21 +01:00
public void doFilter ( ServletRequest request , ServletResponse response ,
FilterChain chain ) throws IOException , ServletException {
2020-06-22 15:47:34 +02:00
2016-10-03 16:22:42 +02:00
String token = request . getParameter ( TOKEN_HEADER ) = = null ? ( ( HttpServletRequest ) request ) . getHeader ( TOKEN_HEADER ) :
request . getParameter ( TOKEN_HEADER ) ;
2019-12-09 18:06:21 +01:00
long startTime = System . currentTimeMillis ( ) ;
2020-01-17 16:56:46 +01:00
String callerIp = ( ( HttpServletRequest ) request ) . getHeader ( " x-forwarded-for " ) ;
if ( callerIp = = null )
callerIp = request . getRemoteHost ( ) ;
log . info ( " caller ip {} " , callerIp ) ;
2016-10-03 16:22:42 +02:00
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 ) ;
2020-01-17 16:56:46 +01:00
2016-10-03 16:22:42 +02:00
String pathInfo = ( ( HttpServletRequest ) request ) . getPathInfo ( ) ;
2020-01-17 16:56:46 +01:00
String servletPath = ( ( HttpServletRequest ) request ) . getServletPath ( ) ;
2016-11-25 15:34:11 +01:00
if ( pathInfo = = null | | pathInfo . isEmpty ( ) ) {
2020-01-17 16:56:46 +01:00
pathInfo = servletPath . replace ( " /gcube/service " , " " ) ;
log . info ( " called path info {} " , pathInfo ) ;
if ( pathInfo = = null | | pathInfo . isEmpty ( ) ) {
2020-06-22 15:47:34 +02:00
( ( HttpServletResponse ) response ) . sendError ( HttpServletResponse . SC_INTERNAL_SERVER_ERROR ) ;
log . error ( " call rejected from filters: invalid path " ) ;
generateAccounting ( " Unknown " , " Unknown " , callerIp , false , startTime , request . getLocalName ( ) ) ;
2020-01-17 16:56:46 +01:00
return ;
}
2016-11-25 15:34:11 +01:00
}
2020-06-22 15:47:34 +02:00
2016-11-25 15:34:11 +01:00
2016-10-03 16:22:42 +02:00
if ( requiresToken ( pathInfo ) & & token = = null ) {
( ( HttpServletResponse ) response ) . sendError ( HttpServletResponse . SC_UNAUTHORIZED ) ;
2020-06-22 15:47:34 +02:00
log . error ( " call rejected from filters, call requires caller token " ) ;
generateAccounting ( " Unknown " , " Unknown " , callerIp , false , startTime , request . getLocalName ( ) ) ;
2016-10-03 16:22:42 +02:00
return ;
}
2020-01-17 16:56:46 +01:00
2016-10-03 16:22:42 +02:00
/ * 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 ) ;
2020-06-22 15:47:34 +02:00
log . error ( " call rejected from filters " ) ;
generateAccounting ( " Unknown " , " Unknown " , callerIp , false , startTime , request . getLocalName ( ) ) ;
2016-10-03 16:22:42 +02:00
return ;
}
chain . doFilter ( request , response ) ;
2020-06-22 15:47:34 +02:00
generateAccounting ( " Unknown " , " Unknown " , callerIp , true , startTime , request . getLocalName ( ) ) ;
2019-12-09 18:06:21 +01:00
2016-10-03 16:22:42 +02:00
}
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 ;
}
2016-11-25 15:34:11 +01:00
//TODO: review it, something is not working check if is correct that they are in OR
2016-10-03 16:22:42 +02:00
private boolean checkAllowed ( String pathInfo , String callerIp , AuthorizationEntry info ) {
AuthorizationConfiguration conf = ConfigurationHolder . getConfiguration ( ) ;
List < AuthorizationRule > rules = conf . getAuthorizationRules ( ) ;
for ( AuthorizationRule rule : rules ) {
2016-11-25 15:34:11 +01:00
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 ;
}
2016-10-03 16:22:42 +02:00
}
2016-11-25 15:34:11 +01:00
//IF a servlet path matches the caller is not allowed to that servlet (the call should be rejected)
return false ;
2016-10-03 16:22:42 +02:00
}
}
}
return true ;
}
2016-11-25 15:34:11 +01:00
2016-10-03 16:22:42 +02:00
private static boolean checkIpInRange ( String ip , String mask ) {
2016-11-25 15:34:11 +01:00
2016-10-03 16:22:42 +02:00
String [ ] maskArray = mask . split ( " \\ . " ) ;
String [ ] ipArray = ip . split ( " \\ . " ) ;
2016-11-25 15:34:11 +01:00
2016-10-03 16:22:42 +02:00
int [ ] maskByte = new int [ 4 ] ;
int [ ] ipByte = new int [ 4 ] ;
2016-11-25 15:34:11 +01:00
2016-10-03 16:22:42 +02:00
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 ( ) { }
2019-12-09 18:06:21 +01:00
void generateAccounting ( String caller , String callerQualifier , String remoteHost , boolean success , long startTime , String host ) {
2020-06-22 15:47:34 +02:00
/ * AuthorizationConfiguration conf = ConfigurationHolder . getConfiguration ( ) ;
2019-12-09 18:06:21 +01:00
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 ) ;
}
2020-06-22 15:47:34 +02:00
* /
log . info ( " REQUEST SERVED for method {} in {} ms with result {} " , CalledMethodProvider . instance . get ( ) , System . currentTimeMillis ( ) - startTime , success ? OperationResult . SUCCESS : OperationResult . FAILED ) ;
2019-12-09 18:06:21 +01:00
}
2016-10-03 16:22:42 +02:00
}