-
-
Notifications
You must be signed in to change notification settings - Fork 106
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #824 from scalecube/refactor-authentication-internals
Enhanced ServiceMethodInvoker: added support of composite auth context
- Loading branch information
Showing
11 changed files
with
280 additions
and
55 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
31 changes: 31 additions & 0 deletions
31
services-examples/src/main/java/io/scalecube/services/examples/auth/CompositeProfile.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package io.scalecube.services.examples.auth; | ||
|
||
import java.util.StringJoiner; | ||
|
||
public class CompositeProfile { | ||
|
||
private final ServiceEndpointProfile serviceEndpointProfile; | ||
private final UserProfile userProfile; | ||
|
||
public CompositeProfile( | ||
ServiceEndpointProfile serviceEndpointProfile, UserProfile userProfile) { | ||
this.serviceEndpointProfile = serviceEndpointProfile; | ||
this.userProfile = userProfile; | ||
} | ||
|
||
public ServiceEndpointProfile serviceEndpointProfile() { | ||
return serviceEndpointProfile; | ||
} | ||
|
||
public UserProfile userProfile() { | ||
return userProfile; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return new StringJoiner(", ", CompositeProfile.class.getSimpleName() + "[", "]") | ||
.add("serviceEndpointProfile=" + serviceEndpointProfile) | ||
.add("userProfile=" + userProfile) | ||
.toString(); | ||
} | ||
} |
113 changes: 113 additions & 0 deletions
113
...amples/src/main/java/io/scalecube/services/examples/auth/CompositeProfileAuthExample.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
package io.scalecube.services.examples.auth; | ||
|
||
import static io.scalecube.services.auth.MonoAuthUtil.deferWithPrincipal; | ||
|
||
import io.scalecube.services.Microservices; | ||
import io.scalecube.services.ServiceEndpoint; | ||
import io.scalecube.services.ServiceInfo; | ||
import io.scalecube.services.api.ServiceMessage; | ||
import io.scalecube.services.auth.Authenticator; | ||
import io.scalecube.services.auth.CredentialsSupplier; | ||
import io.scalecube.services.discovery.ScalecubeServiceDiscovery; | ||
import io.scalecube.services.exceptions.UnauthorizedException; | ||
import io.scalecube.services.transport.rsocket.RSocketServiceTransport; | ||
import io.scalecube.transport.netty.websocket.WebsocketTransportFactory; | ||
import java.time.Duration; | ||
import java.util.Collections; | ||
import reactor.core.publisher.Mono; | ||
|
||
public class CompositeProfileAuthExample { | ||
|
||
/** | ||
* Main program. | ||
* | ||
* @param args arguments | ||
*/ | ||
public static void main(String[] args) { | ||
Microservices service = | ||
Microservices.builder() | ||
.discovery( | ||
serviceEndpoint -> | ||
new ScalecubeServiceDiscovery() | ||
.transport(cfg -> cfg.transportFactory(new WebsocketTransportFactory())) | ||
.options(opts -> opts.metadata(serviceEndpoint))) | ||
.transport(() -> new RSocketServiceTransport().authenticator(authenticator())) | ||
.services( | ||
call -> | ||
Collections.singletonList( | ||
ServiceInfo.fromServiceInstance(new SecuredServiceByCompositeProfileImpl()) | ||
.authenticator(compositeAuthenticator()) | ||
.build())) | ||
.startAwait(); | ||
|
||
Microservices caller = | ||
Microservices.builder() | ||
.discovery(endpoint -> discovery(service, endpoint)) | ||
.transport( | ||
() -> new RSocketServiceTransport().credentialsSupplier(credentialsSupplier())) | ||
.startAwait(); | ||
|
||
ServiceMessage response = | ||
caller | ||
.call() | ||
.requestOne( | ||
ServiceMessage.builder() | ||
.qualifier("securedServiceByCompositeProfile/hello") | ||
.header("userProfile.name", "SEGA") | ||
.header("userProfile.role", "ADMIN") | ||
.data("hello world") | ||
.build(), | ||
String.class) | ||
.block(Duration.ofSeconds(3)); | ||
|
||
System.err.println("### Received 'caller' response: " + response.data()); | ||
} | ||
|
||
private static Authenticator<ServiceEndpointProfile> authenticator() { | ||
return headers -> { | ||
String transportSessionKey = headers.get("transportSessionKey"); | ||
|
||
if ("asdf7hasd9hasd7fha8ds7fahsdf87".equals(transportSessionKey)) { | ||
return Mono.just(new ServiceEndpointProfile("endpoint123", "operations")); | ||
} | ||
|
||
return Mono.error( | ||
new UnauthorizedException("Authentication failed (transportSessionKey incorrect)")); | ||
}; | ||
} | ||
|
||
private static CredentialsSupplier credentialsSupplier() { | ||
return service -> | ||
Mono.just( | ||
Collections.singletonMap("transportSessionKey", "asdf7hasd9hasd7fha8ds7fahsdf87")); | ||
} | ||
|
||
private static Authenticator<CompositeProfile> compositeAuthenticator() { | ||
return headers -> | ||
deferWithPrincipal(ServiceEndpointProfile.class) | ||
.flatMap( | ||
serviceEndpointProfile -> { | ||
|
||
// If userProfile not set then throw error | ||
if (!headers.containsKey("userProfile.name") | ||
|| !headers.containsKey("userProfile.role")) { | ||
throw new UnauthorizedException("userProfile not found or invalid"); | ||
} | ||
|
||
// Otherwise return new combined profile which will be stored under | ||
// AUTH_CONTEXT_KEY | ||
|
||
return Mono.just( | ||
new CompositeProfile( | ||
serviceEndpointProfile, UserProfile.fromHeaders(headers))); | ||
}); | ||
} | ||
|
||
private static ScalecubeServiceDiscovery discovery( | ||
Microservices service, ServiceEndpoint endpoint) { | ||
return new ScalecubeServiceDiscovery() | ||
.transport(cfg -> cfg.transportFactory(new WebsocketTransportFactory())) | ||
.options(opts -> opts.metadata(endpoint)) | ||
.membership(opts -> opts.seedMembers(service.discovery().address())); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
14 changes: 14 additions & 0 deletions
14
...s/src/main/java/io/scalecube/services/examples/auth/SecuredServiceByCompositeProfile.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
package io.scalecube.services.examples.auth; | ||
|
||
import io.scalecube.services.annotations.Service; | ||
import io.scalecube.services.annotations.ServiceMethod; | ||
import io.scalecube.services.auth.Secured; | ||
import reactor.core.publisher.Mono; | ||
|
||
@Secured | ||
@Service("securedServiceByCompositeProfile") | ||
public interface SecuredServiceByCompositeProfile { | ||
|
||
@ServiceMethod | ||
Mono<String> hello(String name); | ||
} |
34 changes: 34 additions & 0 deletions
34
...c/main/java/io/scalecube/services/examples/auth/SecuredServiceByCompositeProfileImpl.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
package io.scalecube.services.examples.auth; | ||
|
||
import io.scalecube.services.auth.MonoAuthUtil; | ||
import io.scalecube.services.exceptions.ForbiddenException; | ||
import reactor.core.publisher.Mono; | ||
|
||
public class SecuredServiceByCompositeProfileImpl implements SecuredServiceByCompositeProfile { | ||
|
||
@Override | ||
public Mono<String> hello(String name) { | ||
return MonoAuthUtil.deferWithPrincipal(CompositeProfile.class) | ||
.flatMap( | ||
compositeProfile -> { | ||
final UserProfile userProfile = compositeProfile.userProfile(); | ||
final ServiceEndpointProfile serviceEndpointProfile = | ||
compositeProfile.serviceEndpointProfile(); | ||
checkPermissions(userProfile); | ||
return Mono.just( | ||
"Hello, name=" | ||
+ name | ||
+ " (userProfile=" | ||
+ userProfile | ||
+ ", serviceEndpointProfile=" | ||
+ serviceEndpointProfile | ||
+ ")"); | ||
}); | ||
} | ||
|
||
private void checkPermissions(UserProfile user) { | ||
if (!user.role().equals("ADMIN")) { | ||
throw new ForbiddenException("Forbidden"); | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
30 changes: 30 additions & 0 deletions
30
...es-examples/src/main/java/io/scalecube/services/examples/auth/ServiceEndpointProfile.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package io.scalecube.services.examples.auth; | ||
|
||
import java.util.StringJoiner; | ||
|
||
public class ServiceEndpointProfile { | ||
|
||
private final String endpoint; | ||
private final String serviceRole; | ||
|
||
public ServiceEndpointProfile(String endpoint, String serviceRole) { | ||
this.endpoint = endpoint; | ||
this.serviceRole = serviceRole; | ||
} | ||
|
||
public String endpoint() { | ||
return endpoint; | ||
} | ||
|
||
public String serviceRole() { | ||
return serviceRole; | ||
} | ||
|
||
@Override | ||
public String toString() { | ||
return new StringJoiner(", ", ServiceEndpointProfile.class.getSimpleName() + "[", "]") | ||
.add("endpoint='" + endpoint + "'") | ||
.add("serviceRole='" + serviceRole + "'") | ||
.toString(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.