Skip to content

Commit ca82199

Browse files
jvmletAlexander Furer
andauthored
Spring boot security (#155)
SB security integration Co-authored-by: Alexander Furer <[email protected]>
1 parent 38b958e commit ca82199

File tree

72 files changed

+2585
-237
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

72 files changed

+2585
-237
lines changed

README.adoc

Lines changed: 218 additions & 34 deletions
Large diffs are not rendered by default.

build.gradle

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,7 @@
11
buildscript {
22
ext {
3-
springBoot_1_X_Version = '1.5.13.RELEASE'
4-
springBoot_2_X_Version = '2.1.3.RELEASE'
5-
grpcVersion = '1.31.1'
3+
springBoot_2_X_Version = '2.3.3.RELEASE'
4+
grpcVersion = '1.32.1'
65
}
76
repositories {
87
mavenCentral()
@@ -39,6 +38,8 @@ allprojects {
3938
mavenCentral()
4039
jcenter()
4140
maven { url "https://repo.spring.io/milestone" }
41+
maven { url "https://jitpack.io" }
42+
4243
}
4344
}
4445

@@ -69,7 +70,8 @@ subprojects {
6970
task codeCoverageReport(type: JacocoReport) {
7071
executionData fileTree(project.rootDir.absolutePath).include("**/build/jacoco/*.exec")
7172

72-
sourceSets project('grpc-spring-boot-starter').sourceSets.main
73+
sourceSets (project('grpc-spring-boot-starter').sourceSets.main
74+
,project('grpc-client-spring-boot-starter').sourceSets.main)
7375

7476
//subprojects.each {
7577
//sourceSets it.sourceSets.main
@@ -78,7 +80,7 @@ task codeCoverageReport(type: JacocoReport) {
7880
reports {
7981
xml.enabled true
8082
xml.destination = new File(buildDir,"reports/jacoco/report.xml")
81-
html.enabled false
83+
html.enabled true
8284
csv.enabled false
8385
}
8486
}

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
version=3.5.8-SNAPSHOT
1+
version=4.0.0-SNAPSHOT
22
group=io.github.lognet
33
description=Spring Boot starter for Google RPC.
44
gitHubUrl=https\://github.com/LogNet/grpc-spring-boot-starter
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
buildscript {
2+
repositories {
3+
gradlePluginPortal()
4+
mavenCentral()
5+
}
6+
dependencies {
7+
8+
classpath "io.franzbecker:gradle-lombok:4.0.0"
9+
}
10+
}
11+
12+
apply plugin: 'java'
13+
apply plugin: 'maven-publish'
14+
apply plugin: 'signing'
15+
apply plugin: "de.marcphilipp.nexus-publish"
16+
apply plugin: 'io.franzbecker.gradle-lombok'
17+
18+
task delombok(type: io.franzbecker.gradle.lombok.task.DelombokTask) {
19+
def outputDir = file("$buildDir/delombok")
20+
outputs.dir(outputDir)
21+
for (srcDir in project.sourceSets.main.java.srcDirs) {
22+
inputs.dir(srcDir)
23+
args(srcDir, "-d", outputDir)
24+
}
25+
doFirst {
26+
outputDir.deleteDir()
27+
}
28+
}
29+
30+
task sourceJar(type: Jar) {
31+
classifier "sources"
32+
from delombok
33+
}
34+
35+
task javadocJar(type: Jar, dependsOn: javadoc) {
36+
classifier "javadoc"
37+
from javadoc.destinationDir
38+
}
39+
40+
artifacts {
41+
archives jar
42+
archives sourceJar
43+
archives javadocJar
44+
}
45+
signing {
46+
sign configurations.archives
47+
}
48+
49+
50+
nexusPublishing {
51+
clientTimeout = java.time.Duration.ofMinutes(7)
52+
repositories {
53+
sonatype()
54+
}
55+
56+
}
57+
58+
publishing {
59+
publications {
60+
mavenJava(MavenPublication) {
61+
pom {
62+
name = 'grpc-spring-boot-starter'
63+
description = 'grpc-spring-boot-starter'
64+
url = 'https://github.com/LogNet/grpc-spring-boot-starter'
65+
66+
scm {
67+
url = 'https://github.com/LogNet/grpc-spring-boot-starter'
68+
connection = 'scm:https://[email protected]/LogNet/grpc-spring-boot-starter.git'
69+
developerConnection = 'scm:git://github.com/LogNet/grpc-spring-boot-starter.git'
70+
}
71+
72+
licenses {
73+
license {
74+
name = 'The Apache Software License, Version 2.0'
75+
url = 'http://www.apache.org/licenses/LICENSE-2.0.txt'
76+
distribution = 'repo'
77+
}
78+
}
79+
80+
developers {
81+
developer {
82+
id = 'jvmlet'
83+
name = 'Furer Alexander'
84+
85+
}
86+
}
87+
88+
}
89+
90+
from components.java
91+
92+
93+
artifact(sourceJar) {
94+
classifier = 'sources'
95+
}
96+
artifact(javadocJar) {
97+
classifier = 'javadoc'
98+
}
99+
}
100+
}
101+
}
102+
103+
signing {
104+
required {
105+
// signing is required if this is a release version and the artifacts are to be published
106+
!version.toString().endsWith('-SNAPSHOT') && tasks.withType(PublishToMavenRepository).find {
107+
gradle.taskGraph.hasTask it
108+
}
109+
}
110+
sign publishing.publications
111+
}
112+
113+
114+
dependencies {
115+
compile "io.grpc:grpc-api:${grpcVersion}"
116+
}
117+
compileJava.dependsOn(processResources)
118+
119+
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
package org.lognet.springboot.grpc.security;
2+
3+
import io.grpc.CallCredentials;
4+
import io.grpc.Metadata;
5+
import io.grpc.Status;
6+
7+
import java.util.concurrent.Executor;
8+
9+
/**
10+
* Adds Authorization header with configured configured authentication scheme token supplied by tokeSupplier
11+
*/
12+
13+
public class AuthCallCredentials extends CallCredentials {
14+
private AuthHeader authHeader;
15+
16+
public AuthCallCredentials(AuthHeader.AuthHeaderBuilder authHeaderBuilder) {
17+
this(authHeaderBuilder.build());
18+
}
19+
public AuthCallCredentials(AuthHeader authHeader) {
20+
this.authHeader = authHeader;
21+
}
22+
23+
@Override
24+
public void applyRequestMetadata(RequestInfo requestInfo, Executor appExecutor, MetadataApplier metadataApplier) {
25+
26+
appExecutor.execute(()->{
27+
try {
28+
metadataApplier.apply(authHeader.attach(new Metadata()));
29+
} catch (Throwable e) {
30+
metadataApplier.fail(Status.UNAUTHENTICATED.withCause(e));
31+
}
32+
}
33+
);
34+
35+
36+
37+
}
38+
39+
@Override
40+
public void thisUsesUnstableApi() {
41+
// noop
42+
}
43+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package org.lognet.springboot.grpc.security;
2+
3+
import io.grpc.CallOptions;
4+
import io.grpc.Channel;
5+
import io.grpc.ClientCall;
6+
import io.grpc.ClientInterceptor;
7+
import io.grpc.ClientInterceptors;
8+
import io.grpc.Metadata;
9+
import io.grpc.MethodDescriptor;
10+
11+
/**
12+
* Adds Authorization header with configured authentication scheme token supplied by tokeSupplier to each intercepted client call
13+
*/
14+
15+
16+
public class AuthClientInterceptor implements ClientInterceptor {
17+
private AuthHeader authHeader;
18+
19+
public AuthClientInterceptor(AuthHeader authHeader) {
20+
this.authHeader = authHeader;
21+
}
22+
public AuthClientInterceptor(AuthHeader.AuthHeaderBuilder authHeaderBuilder) {
23+
this(authHeaderBuilder.build());
24+
}
25+
26+
@Override
27+
public <ReqT, RespT> ClientCall<ReqT, RespT> interceptCall(MethodDescriptor<ReqT, RespT> methodDescriptor, CallOptions callOptions, Channel next) {
28+
return new ClientInterceptors.CheckedForwardingClientCall<ReqT, RespT>(next.newCall(methodDescriptor, callOptions)) {
29+
@Override
30+
protected void checkedStart(Listener<RespT> responseListener, Metadata headers) throws Exception {
31+
delegate().start(responseListener, authHeader.attach(headers));
32+
}
33+
};
34+
}
35+
}
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
package org.lognet.springboot.grpc.security;
2+
3+
import io.grpc.Metadata;
4+
import lombok.Builder;
5+
6+
import java.nio.ByteBuffer;
7+
import java.util.Base64;
8+
import java.util.function.Supplier;
9+
10+
@Builder
11+
public class AuthHeader implements Constants {
12+
private final Supplier<ByteBuffer> tokenSupplier;
13+
private final String authScheme;
14+
15+
public static class AuthHeaderBuilder {
16+
17+
public AuthHeader.AuthHeaderBuilder bearer() {
18+
return authScheme(Constants.BEARER_AUTH_SCHEME);
19+
}
20+
public AuthHeader.AuthHeaderBuilder basic() {
21+
return authScheme(Constants.BASIC_AUTH_SCHEME);
22+
}
23+
24+
public AuthHeader.AuthHeaderBuilder basic(String userName, byte[] password) {
25+
final ByteBuffer buffer = ByteBuffer.allocate(userName.length() + password.length + 1)
26+
.put(userName.getBytes())
27+
.put((byte) ':')
28+
.put(password);
29+
buffer.rewind();
30+
ByteBuffer token = Base64.getEncoder().encode(buffer);
31+
return authScheme(Constants.BASIC_AUTH_SCHEME)
32+
.tokenSupplier(() -> {
33+
token.rewind();
34+
return token;
35+
});
36+
}
37+
38+
39+
}
40+
public Metadata attach(Metadata metadataHeader){
41+
byte[] token = tokenSupplier.get().array();
42+
final byte[] header = ByteBuffer.allocate(authScheme.length() + token.length + 1)
43+
.put(authScheme.getBytes())
44+
.put((byte) ' ')
45+
.put(token)
46+
.array();
47+
metadataHeader.put(Constants.AUTH_HEADER_KEY,header);
48+
return metadataHeader;
49+
}
50+
}
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
package org.lognet.springboot.grpc.security;
2+
3+
import io.grpc.Metadata;
4+
5+
6+
public interface Constants {
7+
Metadata.Key<byte[]> AUTH_HEADER_KEY = Metadata.Key.of("Authorization"+Metadata.BINARY_HEADER_SUFFIX, Metadata.BINARY_BYTE_MARSHALLER);
8+
String BEARER_AUTH_SCHEME="Bearer";
9+
String BASIC_AUTH_SCHEME="Basic";
10+
11+
12+
13+
}

grpc-spring-boot-starter-demo/build.gradle

Lines changed: 32 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,23 +4,51 @@ buildscript {
44
mavenCentral()
55
}
66
dependencies {
7-
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBoot_1_X_Version}")
7+
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBoot_2_X_Version}")
88
}
99
}
10+
apply plugin: 'java'
1011
apply plugin: 'com.google.protobuf'
1112
apply plugin: 'org.springframework.boot'
13+
apply plugin: 'io.spring.dependency-management'
14+
ext {
15+
set('springCloudVersion', "Hoxton.SR6")
1216

17+
}
1318
dependencies {
1419

1520
compile "org.springframework.boot:spring-boot-starter-actuator"
1621
compile 'org.springframework.boot:spring-boot-starter-web'
1722

23+
compile "org.springframework.security:spring-security-config"
24+
compile "org.springframework.security:spring-security-oauth2-jose"
25+
compile "org.springframework.security:spring-security-oauth2-resource-server"
26+
1827

1928
compile project(':grpc-spring-boot-starter')
29+
compile project(':grpc-client-spring-boot-starter')
2030

2131
testCompile 'org.springframework.boot:spring-boot-starter-aop'
2232
testCompile 'org.springframework.boot:spring-boot-starter-test'
2333
testCompile 'com.github.stefanbirkner:system-rules:1.18.0'
34+
testCompile('org.springframework.cloud:spring-cloud-starter-consul-discovery')
35+
testCompile 'com.pszymczyk.consul:embedded-consul:2.1.4'
36+
37+
testCompile "org.springframework.cloud:spring-cloud-config-server:2.1.1.RELEASE"
38+
testCompile "org.springframework.cloud:spring-cloud-config-client:2.1.1.RELEASE"
39+
testCompile "com.playtika.testcontainers:embedded-keycloak:1.76"
40+
testRuntime "org.springframework.cloud:spring-cloud-starter"
41+
42+
43+
44+
testImplementation 'org.hamcrest:hamcrest:2.1'
45+
46+
testImplementation 'org.mockito:mockito-core:2.23.0'
47+
48+
49+
50+
//testCompile "org.testcontainers:junit-jupiter:1.14.3"
51+
2452
}
2553
sourceSets {
2654
main {
@@ -63,16 +91,16 @@ task cleanProtoGen{
6391
}
6492
}
6593
clean.dependsOn cleanProtoGen
66-
bootRepackage.enabled =false
94+
6795

6896
dependencyManagement {
6997
imports {
70-
mavenBom "org.springframework.boot:spring-boot-starter-parent:${springBoot_1_X_Version}"
98+
mavenBom "org.springframework.boot:spring-boot-starter-parent:${springBoot_2_X_Version}"
99+
mavenBom "org.springframework.cloud:spring-cloud-dependencies:${springCloudVersion}"
71100
}
72101
}
73102

74103

75104

76105

77106

78-

grpc-spring-boot-starter-demo/src/main/java/org/lognet/springboot/grpc/demo/DemoAppConfiguration.java

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,11 @@
44
import io.grpc.examples.CalculatorOuterClass;
55
import io.grpc.stub.StreamObserver;
66
import org.lognet.springboot.grpc.GRpcService;
7-
import org.springframework.context.annotation.Bean;
87
import org.springframework.context.annotation.Configuration;
98

109
@Configuration
1110
public class DemoAppConfiguration {
12-
@Bean
13-
public GreeterService greeterService() {
14-
return new GreeterService();
15-
}
11+
1612

1713
@GRpcService(interceptors = NotSpringBeanInterceptor.class)
1814
public static class CalculatorService extends CalculatorGrpc.CalculatorImplBase{

0 commit comments

Comments
 (0)