Skip to content
This repository was archived by the owner on May 22, 2021. It is now read-only.

Commit ed95d43

Browse files
committed
Added spring-auth module (#14)
1 parent c899ff6 commit ed95d43

9 files changed

Lines changed: 301 additions & 0 deletions

File tree

pom.xml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
<module>scope</module>
1414
<module>auth</module>
1515
<module>util</module>
16+
<module>spring-auth</module>
1617
</modules>
1718

1819
<properties>

spring-auth/pom.xml

Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<project xmlns="http://maven.apache.org/POM/4.0.0"
3+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4+
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
5+
<parent>
6+
<artifactId>gewia-common</artifactId>
7+
<groupId>com.gewia.common</groupId>
8+
<version>1.0</version>
9+
</parent>
10+
<modelVersion>4.0.0</modelVersion>
11+
<artifactId>spring-auth</artifactId>
12+
13+
<dependencyManagement>
14+
<dependencies>
15+
<dependency>
16+
<groupId>org.springframework.boot</groupId>
17+
<artifactId>spring-boot-dependencies</artifactId>
18+
<version>2.1.10.RELEASE</version>
19+
<type>pom</type>
20+
<scope>import</scope>
21+
</dependency>
22+
</dependencies>
23+
</dependencyManagement>
24+
25+
<dependencies>
26+
<dependency>
27+
<groupId>com.gewia.common</groupId>
28+
<artifactId>auth</artifactId>
29+
<version>${project.parent.version}</version>
30+
<scope>compile</scope>
31+
</dependency>
32+
<dependency>
33+
<groupId>com.gewia.common</groupId>
34+
<artifactId>scope</artifactId>
35+
<version>${project.parent.version}</version>
36+
<scope>compile</scope>
37+
</dependency>
38+
39+
<dependency>
40+
<groupId>com.auth0</groupId>
41+
<artifactId>java-jwt</artifactId>
42+
<version>3.10.3</version>
43+
<scope>compile</scope>
44+
</dependency>
45+
46+
<dependency>
47+
<groupId>javax.validation</groupId>
48+
<artifactId>validation-api</artifactId>
49+
<version>2.0.1.Final</version>
50+
<scope>compile</scope>
51+
</dependency>
52+
53+
<!-- Spring -->
54+
<dependency>
55+
<groupId>org.springframework.boot</groupId>
56+
<artifactId>spring-boot-starter-web</artifactId>
57+
<exclusions>
58+
<exclusion>
59+
<groupId>org.springframework.boot</groupId>
60+
<artifactId>spring-boot-starter-logging</artifactId>
61+
</exclusion>
62+
</exclusions>
63+
</dependency>
64+
<dependency>
65+
<groupId>org.springframework.boot</groupId>
66+
<artifactId>spring-boot-starter-test</artifactId>
67+
<scope>test</scope>
68+
<exclusions>
69+
<exclusion>
70+
<groupId>org.junit.vintage</groupId>
71+
<artifactId>junit-vintage-engine</artifactId>
72+
</exclusion>
73+
</exclusions>
74+
</dependency>
75+
</dependencies>
76+
77+
</project>
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.gewia.common.spring.auth;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Repeatable;
5+
import java.lang.annotation.Retention;
6+
import java.lang.annotation.RetentionPolicy;
7+
import java.lang.annotation.Target;
8+
9+
@Retention(RetentionPolicy.RUNTIME)
10+
@Target(ElementType.METHOD)
11+
@Repeatable(Authentication.class)
12+
public @interface AuthScope {
13+
14+
String value() default "";
15+
16+
String scope() default "";
17+
18+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package com.gewia.common.spring.auth;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Retention(RetentionPolicy.RUNTIME)
9+
@Target(ElementType.METHOD)
10+
public @interface Authentication {
11+
12+
AuthScope[] value();
13+
14+
}
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
package com.gewia.common.spring.auth;
2+
3+
import java.lang.annotation.ElementType;
4+
import java.lang.annotation.Retention;
5+
import java.lang.annotation.RetentionPolicy;
6+
import java.lang.annotation.Target;
7+
8+
@Retention(RetentionPolicy.RUNTIME)
9+
@Target({ElementType.METHOD, ElementType.TYPE})
10+
public @interface IgnoreServiceToken {
11+
12+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.gewia.common.spring.auth;
2+
3+
import java.util.ArrayList;
4+
import java.util.List;
5+
import lombok.AccessLevel;
6+
import lombok.Getter;
7+
import org.springframework.beans.factory.InitializingBean;
8+
import org.springframework.context.annotation.ComponentScan;
9+
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
10+
11+
@ComponentScan("com.gewia.common.spring.auth")
12+
public abstract class SpringAuthentication implements InitializingBean {
13+
14+
@Getter(AccessLevel.PACKAGE) private static List<HandlerInterceptorAdapter> interceptors = new ArrayList<>();
15+
16+
@Override
17+
public void afterPropertiesSet() {
18+
interceptors = this.addAuthenticationInterceptors(interceptors);
19+
}
20+
21+
abstract public List<HandlerInterceptorAdapter> addAuthenticationInterceptors(List<HandlerInterceptorAdapter> authenticationInterceptors);
22+
23+
}
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
package com.gewia.common.spring.auth;
2+
3+
import com.auth0.jwt.interfaces.DecodedJWT;
4+
import java.util.List;
5+
import javax.servlet.http.HttpServletRequest;
6+
import org.springframework.context.annotation.Configuration;
7+
import org.springframework.core.MethodParameter;
8+
import org.springframework.web.bind.support.WebDataBinderFactory;
9+
import org.springframework.web.context.request.NativeWebRequest;
10+
import org.springframework.web.method.support.HandlerMethodArgumentResolver;
11+
import org.springframework.web.method.support.ModelAndViewContainer;
12+
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
13+
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
14+
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
15+
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
16+
17+
@Configuration
18+
@EnableWebMvc
19+
public class SpringAuthenticationWebConfig implements WebMvcConfigurer, HandlerMethodArgumentResolver {
20+
21+
@Override
22+
public Object resolveArgument(MethodParameter parameter, ModelAndViewContainer mavContainer, NativeWebRequest webRequest, WebDataBinderFactory binderFactory) throws Exception {
23+
return ((HttpServletRequest) webRequest.getNativeRequest()).getAttribute("accessToken");
24+
}
25+
26+
@Override
27+
public boolean supportsParameter(MethodParameter parameter) {
28+
return parameter.getParameterType().equals(DecodedJWT.class);
29+
}
30+
31+
@Override
32+
public void addArgumentResolvers(List<HandlerMethodArgumentResolver> resolvers) {
33+
resolvers.add(this);
34+
}
35+
36+
@Override
37+
public void addInterceptors(InterceptorRegistry registry) {
38+
for (HandlerInterceptorAdapter interceptors : SpringAuthentication.getInterceptors())
39+
registry.addInterceptor(interceptors).addPathPatterns("/**/*");
40+
}
41+
42+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package com.gewia.common.spring.auth.interceptor;
2+
3+
import com.auth0.jwt.interfaces.Claim;
4+
import com.auth0.jwt.interfaces.DecodedJWT;
5+
import com.gewia.common.auth.jwt.JwtUtil;
6+
import com.gewia.common.spring.auth.AuthScope;
7+
import com.gewia.common.spring.auth.Authentication;
8+
import com.gewia.common.util.Pair;
9+
import java.util.List;
10+
import javax.servlet.http.HttpServletRequest;
11+
import javax.servlet.http.HttpServletResponse;
12+
import lombok.AllArgsConstructor;
13+
import org.springframework.http.HttpStatus;
14+
import org.springframework.web.method.HandlerMethod;
15+
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
16+
17+
@AllArgsConstructor
18+
public class ScopeInterceptor extends HandlerInterceptorAdapter {
19+
20+
private final JwtUtil jwtUtil;
21+
22+
@Override
23+
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
24+
HandlerMethod method = (HandlerMethod) handler;
25+
26+
AuthScope[] authScopes;
27+
Authentication auth = method.getMethodAnnotation(Authentication.class);
28+
AuthScope methodAuthScope = method.getMethodAnnotation(AuthScope.class);
29+
if (auth != null) authScopes = auth.value();
30+
else {
31+
if (methodAuthScope == null) return true;
32+
authScopes = new AuthScope[]{methodAuthScope};
33+
}
34+
35+
36+
String jwt = request.getHeader("Authorization");
37+
if (jwt == null || jwt.isBlank()) return false;
38+
39+
Pair<DecodedJWT, JwtUtil.VerificationResult> result = this.jwtUtil.verify(jwt);
40+
switch (result.getRight()) {
41+
case EXPIRED:
42+
response.setStatus(HttpStatus.UNAUTHORIZED.value());
43+
return false;
44+
case INVALID:
45+
response.setStatus(HttpStatus.NOT_ACCEPTABLE.value());
46+
return false;
47+
case FAILED:
48+
response.setStatus(HttpStatus.EXPECTATION_FAILED.value());
49+
return false;
50+
case UNKNOWN:
51+
response.setStatus(HttpStatus.FORBIDDEN.value());
52+
return false;
53+
default:
54+
response.setStatus(HttpStatus.OK.value());
55+
}
56+
57+
Claim claim = result.getLeft().getClaim("scopes");
58+
List<String> userScopes = claim.asList(String.class);
59+
for (AuthScope authScope : authScopes) {
60+
String scope = authScope.scope();
61+
if (scope.isBlank()) scope = authScope.value();
62+
if (!scope.isBlank()) {
63+
boolean isPresent = false;
64+
for (String userScope : userScopes)
65+
if (userScope.equalsIgnoreCase(scope)) {
66+
isPresent = true;
67+
break;
68+
}
69+
if (!isPresent) return false;
70+
}
71+
}
72+
73+
request.setAttribute("accessToken", result.getLeft());
74+
75+
return true;
76+
}
77+
78+
}
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package com.gewia.common.spring.auth.interceptor;
2+
3+
import com.gewia.common.spring.auth.IgnoreServiceToken;
4+
import javax.servlet.http.HttpServletRequest;
5+
import javax.servlet.http.HttpServletResponse;
6+
import lombok.AllArgsConstructor;
7+
import org.springframework.http.HttpStatus;
8+
import org.springframework.web.method.HandlerMethod;
9+
import org.springframework.web.servlet.handler.HandlerInterceptorAdapter;
10+
11+
@AllArgsConstructor
12+
public class ServiceTokenInterceptor extends HandlerInterceptorAdapter {
13+
14+
private final String serviceToken;
15+
16+
@Override
17+
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
18+
response.setStatus(HttpStatus.FORBIDDEN.value());
19+
20+
HandlerMethod method = (HandlerMethod) handler;
21+
if (method.hasMethodAnnotation(IgnoreServiceToken.class) ||
22+
method.getMethod().getDeclaringClass().getAnnotation(IgnoreServiceToken.class) != null) {
23+
response.setStatus(HttpStatus.OK.value());
24+
return true;
25+
}
26+
27+
String serviceToken = request.getHeader("X-ServiceToken");
28+
29+
if (serviceToken == null) return false;
30+
if (!this.serviceToken.equals(serviceToken)) return false;
31+
32+
response.setStatus(HttpStatus.OK.value());
33+
return true;
34+
}
35+
36+
}

0 commit comments

Comments
 (0)