diff --git a/spring-auth/src/main/java/com/gewia/common/spring/auth/AuthScope.java b/spring-auth/src/main/java/com/gewia/common/spring/auth/AuthScope.java new file mode 100644 index 0000000..8a1116e --- /dev/null +++ b/spring-auth/src/main/java/com/gewia/common/spring/auth/AuthScope.java @@ -0,0 +1,18 @@ +package com.gewia.common.spring.auth; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Repeatable; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +@Repeatable(Authentication.class) +public @interface AuthScope { + + String value() default ""; + + String scope() default ""; + +} diff --git a/spring-auth/src/main/java/com/gewia/common/spring/auth/Authentication.java b/spring-auth/src/main/java/com/gewia/common/spring/auth/Authentication.java index 402418c..cb596e9 100644 --- a/spring-auth/src/main/java/com/gewia/common/spring/auth/Authentication.java +++ b/spring-auth/src/main/java/com/gewia/common/spring/auth/Authentication.java @@ -9,6 +9,6 @@ @Target(ElementType.METHOD) public @interface Authentication { - String scope() default ""; + AuthScope[] value(); } diff --git a/spring-auth/src/main/java/com/gewia/common/spring/auth/IgnoreServiceToken.java b/spring-auth/src/main/java/com/gewia/common/spring/auth/IgnoreServiceToken.java new file mode 100644 index 0000000..e1fee23 --- /dev/null +++ b/spring-auth/src/main/java/com/gewia/common/spring/auth/IgnoreServiceToken.java @@ -0,0 +1,11 @@ +package com.gewia.common.spring.auth; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.METHOD) +public @interface IgnoreServiceToken { +} diff --git a/spring-auth/src/main/java/com/gewia/common/spring/auth/SpringAuthentication.java b/spring-auth/src/main/java/com/gewia/common/spring/auth/SpringAuthentication.java index 4624332..062e238 100644 --- a/spring-auth/src/main/java/com/gewia/common/spring/auth/SpringAuthentication.java +++ b/spring-auth/src/main/java/com/gewia/common/spring/auth/SpringAuthentication.java @@ -1,20 +1,23 @@ package com.gewia.common.spring.auth; -import com.gewia.common.spring.auth.interceptor.AuthenticationInterceptor; import java.util.ArrayList; import java.util.List; -import javax.annotation.PostConstruct; +import lombok.AccessLevel; import lombok.Getter; +import org.springframework.beans.factory.InitializingBean; +import org.springframework.context.annotation.ComponentScan; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; -public abstract class SpringAuthentication { +@ComponentScan("com.gewia.common.spring.auth") +public abstract class SpringAuthentication implements InitializingBean { - @Getter private static List authenticationInterceptors = new ArrayList<>(); + @Getter(AccessLevel.PACKAGE) private static List interceptors = new ArrayList<>(); - @PostConstruct - public void registerInterceptor() { - authenticationInterceptors = this.addAuthenticationInterceptors(authenticationInterceptors); + @Override + public void afterPropertiesSet() throws Exception { + interceptors = this.addAuthenticationInterceptors(interceptors); } - abstract public List addAuthenticationInterceptors(List authenticationInterceptors); + abstract public List addAuthenticationInterceptors(List authenticationInterceptors); } diff --git a/spring-auth/src/main/java/com/gewia/common/spring/auth/SpringAuthenticationWebConfig.java b/spring-auth/src/main/java/com/gewia/common/spring/auth/SpringAuthenticationWebConfig.java index ce718bc..4daa459 100644 --- a/spring-auth/src/main/java/com/gewia/common/spring/auth/SpringAuthenticationWebConfig.java +++ b/spring-auth/src/main/java/com/gewia/common/spring/auth/SpringAuthenticationWebConfig.java @@ -1,7 +1,6 @@ package com.gewia.common.spring.auth; import com.auth0.jwt.interfaces.DecodedJWT; -import com.gewia.common.spring.auth.interceptor.AuthenticationInterceptor; import java.util.List; import javax.servlet.http.HttpServletRequest; import org.springframework.context.annotation.Configuration; @@ -13,6 +12,7 @@ import org.springframework.web.servlet.config.annotation.EnableWebMvc; import org.springframework.web.servlet.config.annotation.InterceptorRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; @Configuration @EnableWebMvc @@ -35,8 +35,8 @@ public void addArgumentResolvers(List resolvers) @Override public void addInterceptors(InterceptorRegistry registry) { - for (AuthenticationInterceptor authenticationInterceptor : SpringAuthentication.getAuthenticationInterceptors()) - registry.addInterceptor(authenticationInterceptor).addPathPatterns("/**/*"); + for (HandlerInterceptorAdapter interceptors : SpringAuthentication.getInterceptors()) + registry.addInterceptor(interceptors).addPathPatterns("/**/*"); } } diff --git a/spring-auth/src/main/java/com/gewia/common/spring/auth/interceptor/AuthenticationInterceptor.java b/spring-auth/src/main/java/com/gewia/common/spring/auth/interceptor/AuthenticationInterceptor.java deleted file mode 100644 index 641f21e..0000000 --- a/spring-auth/src/main/java/com/gewia/common/spring/auth/interceptor/AuthenticationInterceptor.java +++ /dev/null @@ -1,23 +0,0 @@ -package com.gewia.common.spring.auth.interceptor; - -import com.gewia.common.spring.auth.Authentication; -import org.springframework.web.method.HandlerMethod; -import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; -import java.lang.annotation.Annotation; -import java.util.ArrayList; -import java.util.List; - -public class AuthenticationInterceptor extends HandlerInterceptorAdapter { - - public List getAuthenticationAnnotations(Object handler) { - HandlerMethod method = (HandlerMethod) handler; - - List authentications = new ArrayList<>(); - for (Annotation annotation : method.getMethod().getAnnotations()) - if (annotation.annotationType().equals(Authentication.class)) - authentications.add((Authentication) annotation); - - return authentications; - } - -} diff --git a/spring-auth/src/main/java/com/gewia/common/spring/auth/interceptor/AuthenticationScopeInterceptor.java b/spring-auth/src/main/java/com/gewia/common/spring/auth/interceptor/ScopeInterceptor.java similarity index 58% rename from spring-auth/src/main/java/com/gewia/common/spring/auth/interceptor/AuthenticationScopeInterceptor.java rename to spring-auth/src/main/java/com/gewia/common/spring/auth/interceptor/ScopeInterceptor.java index d11cb07..319ed6a 100644 --- a/spring-auth/src/main/java/com/gewia/common/spring/auth/interceptor/AuthenticationScopeInterceptor.java +++ b/spring-auth/src/main/java/com/gewia/common/spring/auth/interceptor/ScopeInterceptor.java @@ -3,6 +3,7 @@ import com.auth0.jwt.interfaces.Claim; import com.auth0.jwt.interfaces.DecodedJWT; import com.gewia.common.auth.jwt.JwtUtil; +import com.gewia.common.spring.auth.AuthScope; import com.gewia.common.spring.auth.Authentication; import com.gewia.common.util.Pair; import java.util.List; @@ -10,9 +11,11 @@ import javax.servlet.http.HttpServletResponse; import lombok.AllArgsConstructor; import org.springframework.http.HttpStatus; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; @AllArgsConstructor -public class AuthenticationScopeInterceptor extends AuthenticationInterceptor { +public class ScopeInterceptor extends HandlerInterceptorAdapter { private JwtUtil jwtUtil; @@ -20,26 +23,36 @@ public class AuthenticationScopeInterceptor extends AuthenticationInterceptor { public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { response.setStatus(HttpStatus.FORBIDDEN.value()); - List authentications = this.getAuthenticationAnnotations(handler); + HandlerMethod method = (HandlerMethod) handler; - if (authentications.isEmpty()) { - response.setStatus(HttpStatus.OK.value()); - return true; + AuthScope[] authScopes; + Authentication auth = method.getMethodAnnotation(Authentication.class); + AuthScope methodAuthScope = method.getMethodAnnotation(AuthScope.class); + if (auth != null) authScopes = auth.value(); + else { + if (methodAuthScope == null) { + response.setStatus(HttpStatus.OK.value()); + return true; + } + authScopes = new AuthScope[]{methodAuthScope}; } + String jwt = request.getHeader("Authorization"); + if (jwt == null || jwt.isBlank()) return false; Pair result = this.jwtUtil.verify(jwt); - if (result.getRight() != JwtUtil.VerificationResult.SUCCESS) return false; Claim claim = result.getLeft().getClaim("scopes"); List userScopes = claim.asList(String.class); - for (Authentication authentication : authentications) { - if (!authentication.scope().isBlank()) { + for (AuthScope authScope : authScopes) { + String scope = authScope.scope(); + if (scope.isBlank()) scope = authScope.value(); + if (!scope.isBlank()) { boolean isPresent = false; for (String userScope : userScopes) - if (userScope.equalsIgnoreCase(authentication.scope())) { + if (userScope.equalsIgnoreCase(scope)) { isPresent = true; break; } diff --git a/spring-auth/src/main/java/com/gewia/common/spring/auth/interceptor/AuthenticationServiceTokenInterceptor.java b/spring-auth/src/main/java/com/gewia/common/spring/auth/interceptor/ServiceTokenInterceptor.java similarity index 61% rename from spring-auth/src/main/java/com/gewia/common/spring/auth/interceptor/AuthenticationServiceTokenInterceptor.java rename to spring-auth/src/main/java/com/gewia/common/spring/auth/interceptor/ServiceTokenInterceptor.java index 466c8f6..2ad9519 100644 --- a/spring-auth/src/main/java/com/gewia/common/spring/auth/interceptor/AuthenticationServiceTokenInterceptor.java +++ b/spring-auth/src/main/java/com/gewia/common/spring/auth/interceptor/ServiceTokenInterceptor.java @@ -1,12 +1,15 @@ package com.gewia.common.spring.auth.interceptor; +import com.gewia.common.spring.auth.IgnoreServiceToken; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import lombok.AllArgsConstructor; import org.springframework.http.HttpStatus; +import org.springframework.web.method.HandlerMethod; +import org.springframework.web.servlet.handler.HandlerInterceptorAdapter; @AllArgsConstructor -public class AuthenticationServiceTokenInterceptor extends AuthenticationInterceptor { +public class ServiceTokenInterceptor extends HandlerInterceptorAdapter { private String serviceToken; @@ -14,6 +17,12 @@ public class AuthenticationServiceTokenInterceptor extends AuthenticationInterce public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { response.setStatus(HttpStatus.FORBIDDEN.value()); + HandlerMethod method = (HandlerMethod) handler; + if (method.hasMethodAnnotation(IgnoreServiceToken.class)) { + response.setStatus(HttpStatus.OK.value()); + return true; + } + String serviceToken = request.getHeader("X-ServiceToken"); if (serviceToken == null) return false;