How can I use RemoteTokenService for more than one client application (with different client_id and secret )?
UPDATE
public ResourceServerTokenServices tokenService() {
RemoteTokenServices tokenServices = new RemoteTokenServices();
tokenServices.setClientId("sample_test_client_app_auth_code");
tokenServices.setClientSecret("secret");
tokenServices.setCheckTokenEndpointUrl("http://localhost:8080/oauth/check_token");
return tokenServices;
}
That's how we configure instance of RemoteTokenService. and inject it to the OAuth2AuthenticationManager for separate Resource server and auth server. Is it correct?
so when some other client has to access this resource how can I configure RemoteTokenService for both of this client.can you provide some light on this. and tell me if I am wrong on something.
The client id in the RemoteTokenServices is not the client that is consuming the resource, it's the client associated with the resource itself (solely for the purpose of authentication of the /check_token endpoint). So once you have it working you can hit that resource from as many clients as you like.
Related
I have two RegisteredClients(and two resource servers):
#Bean
public RegisteredClientRepository registeredClientRepository() {
RegisteredClient spa1 = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("client1")
...
.redirectUri("http://127.0.0.1:3000/authorized")
...
.build();
RegisteredClient spa2 = RegisteredClient.withId(UUID.randomUUID().toString())
.clientId("client2")
...
.redirectUri("http://127.0.0.1:3001/authorized")
...
.build();
return new InMemoryRegisteredClientRepository(spa1, spa2);
}
When I obtain access_token as client1, I can access endpoints in both resource servers.
I need client1 to be able to access only resourceServer1, and client2 to access resourceServer2.
I went through the docs and source code, but I cannot find a way to configure the client to be able to access only certain resource.
I think this was possible in spring security by doing:
#Override
public void configure(ClientDetailsServiceConfigurer clients) throws Exception {
ClientDetailsServiceBuilder.ClientBuilder clientBuilder = clients
.inMemory()
.withClient("client1")
.resourceIds("resourceServer1")
...
Is it doable?
This is usually done by means of the aud claim in the access token.
The client will send the intended audience to the authorization server when it requests an access token, and each resource server must make sure to validate that the aud claim in the access token contains the resource server's ID.
If you use Spring Boot's Resource Server starter I think you can configure the audience ID with the spring.security.oauth2.resourceserver.jwt.audiences property (read more about it here.)
Otherwise, you'll have to look into configuring your own JwtDecoder with its own JwtValidator (which is what validates the JWT claims.)
I have a claim named user_name within my JWT and also corresponding user-name-attribute set as user_name in spring security oauth2 client provider proper property:
spring.security.oauth2.client.provider.my-oauth-provider.user-name-attribute=user_name
I can also see this property is properly being read by ReactiveClientRegistrationRepository class (ClientRegistration.ProviderDetails.UserInfoEndpoint). But when I read SecurityContextHolder.getContext().getAuthentication().getName() on Resource Server I can see the value taken from (default) sub - IdTokenClaimNames.SUB claim.
Why is that? Do I still miss some additional configuration also on resource server side to have specified user-name-attribute taken and returned by SecurityContextHolder.getContext().getAuthentication().getName() on Resource Server? I understand that only Bearer token (and maybe some cookies) is being sent from client to resource server so maybe also some other filter is needed on Gateway/client side - just guessing?
The reason is that you are using a property prefixed with security.oauth2.client, which is intended for OAuth 2.0 Clients.
In Spring Security 5.2.x, there is no Spring Boot property to indicate a user name attribute to Resource Server, e.g. security.oauth2.resourceserver.xyz
You could publish your own Converter to the DSL, though:
JwtAuthenticationConverter converter = new JwtAuthenticationConverter();
http
.oauth2ResourceServer()
.jwtAuthenticationConverter(jwt -> {
JwtAuthenticationToken authentication = converter.convert(jwt);
return new JwtAuthenticationToken(authentication.getToken(),
authentication.getAuthorities(), jwt.getClaim("claim"));
});
I'm creating an application integrating with Shopify's API, which uses OAuth2 for authentication and authorization. Using the tutorial for Spring Security OAuth2, and the tutorial for Shopify, I've been able to get integration working with a single shop. The YAML configuration looks like this:
shopify:
shop: myshop
scopes: read_customers,read_orders
security:
oauth2:
client:
clientId: myclientid
clientSecret: mysecret
tokenName: access_token
authenticationScheme: query
clientAuthenticationScheme: form
accessTokenUri: https://${shopify.shop}.myshopify.com/admin/oauth/access_token
userAuthorizationUri: https://${shopify.shop}.myshopify.com/admin/oauth/authorize?scope=${shopify.scopes}&grant_options[]=
pre-established-redirect-uri: https://myapp/login
registered-redirect-uri: https://myapp/login
use-current-uri: false
resource:
userInfoUri: https://${shopify.shop}.myshopify.com/admin/shop.json
However, this static configuration won't work for an app published in Shopify's App Store because the redirect, access token, user info, and user authorization URIs depend on the shop name. There are examples of using more than one provider, but they still have to be static.
To allow these URI's to be dynamic, I've come up with a few possible options:
Use a parameter in the /login path to identify the shop, then create a filter that adds the shop name to a ThreadLocal that runs before everything else, then dynamically create the AuthorizationCodeResourceDetails that is needed by the OAuth2 filter via a Spring proxied factory bean.
Use a sort of "metafilter" that dynamically recreates the OAuth2ClientAuthenticationProcessingFilter per request along with all of the resources that it needs.
Override OAuth2ClientAuthenticationProcessingFilter so that it can handle recreating the RestTemplate it needs to obtain the access token.
All of these options seem pretty difficult. What's a good way to handle dynamically-generated URI's for access tokens and user information in Spring Security OAuth2?
Also, since I'm new to OAuth2 in general, do I need to enable a Resource Server in my Spring configuration to protect my app with the access token?
a bit late but I did return a dynamic url for an oauth resource by overriding the getter for the Oauth2ProtectedResource
#Bean(name = "googleOauthResource")
public BaseOAuth2ProtectedResourceDetails getGoogleOauthResource() {
final AuthorizationCodeResourceDetails details = new AuthorizationCodeResourceDetails() {
#Override
public String getPreEstablishedRedirectUri() {
final RequestAttributes requestAttributes = RequestContextHolder.getRequestAttributes();
if (requestAttributes instanceof ServletRequestAttributes) {
final HttpServletRequest request = ((ServletRequestAttributes)requestAttributes).getRequest();
return request.getRequestURL() + "?" + request.getQueryString() + "&addStuff";
}
return super.getPreEstablishedRedirectUri();
}
};
details.setId("google-oauth-client");
details.setClientId("xxxxxxxxxxx");
details.setClientSecret("xxxxxxxx");
details.setAccessTokenUri("https://www.googleapis.com/oauth2/v4/token");
details.setUserAuthorizationUri("https://accounts.google.com/o/oauth2/v2/auth");
details.setTokenName("authorization_code");
details.setScope(Arrays.asList("https://mail.google.com/,https://www.googleapis.com/auth/gmail.modify"));
details.setPreEstablishedRedirectUri("http://localhost:8080/xxx-api-web/v2/gmail"); //TODO
details.setUseCurrentUri(false);
details.setAuthenticationScheme(AuthenticationScheme.query);
details.setClientAuthenticationScheme(AuthenticationScheme.form);
details.setGrantType("authorization_code");
return details;
}
I'm having the same problem you are and I'm leaning toward your first theory of using ThreadLocal storage. Here is how I'll probably go about my solution:
Set values from ServletRequest in LocalThread storage by overriding methods in OAuth2ClientAuthenticationProcessingFilter:
attemptAuthentication
successfulAuthentication
unsuccessfulAuthentication
requiresAuthentication
Then translate the URI's within the OAuth2RestTemplate by overriding the followign methods:
createRequest
doExecute
appendQueryParameter
I'll probably have to make my own #Bean for the RestTemplate that has an injected #Service that will lookup the dynamic Shopify domain.
I'll post my solution if it works.
I've created an OAuth2 authorization server using DotNetOpenAuth, which is working fine - I'm using the resource owner password flow, and successfully exchanging user credentials for an access token.
I now want to use that access token to retrieve data from secure endpoints in a ServiceStack API, and I can't work out how to do so. I've examined the Facebook, Google, etc. providers included with ServiceStack but it's not clear whether I should be following the same pattern or not.
What I'm trying to achieve (I think!) is
OAuth client (my app) asks resource owner ('Catherine Smith') for credentials
Client submits request to authorization server, receives an access token
Client requests a secure resource from the resource server (GET /users/csmith/photos)
The access token is included in an HTTP header, e.g. Authorization: Bearer 1234abcd...
The resource server decrypts the access token to verify the identity of the resource owner
The resource server checks that the resource owner has access to the requested resource
The resource server returns the resource to the client
Steps 1 and 2 are working, but I can't work out how to integrate the DotNetOpenAuth resource server code with the ServiceStack authorization framework.
Is there an example somewhere of how I would achieve this? I've found a similar StackOverflow post at How to build secured api using ServiceStack as resource server with OAuth2.0? but it isn't a complete solution and doesn't seem to use the ServiceStack authorization provider model.
EDIT: A little more detail. There's two different web apps in play here. One is the authentication/authorisation server - this doesn't host any customer data (i.e. no data API), but exposes the /oauth/token method that will accept a username/password and return an OAuth2 access token and refresh token, and also provides token-refresh capability. This is built on ASP.NET MVC because it's almost identical to the AuthorizationServer sample included with DotNetOpenAuth. This might be replaced later, but for now it's ASP.NET MVC.
For the actual data API, I'm using ServiceStack because I find it much better than WebAPI or MVC for exposing ReSTful data services.
So in the following example:
the Client is a desktop application running on a user's local machine, the Auth server is ASP.NET MVC + DotNetOpenAuth, and the Resource server is ServiceStack
The particular snippet of DotNetOpenAuth code that's required is:
// scopes is the specific OAuth2 scope associated with the current API call.
var scopes = new string[] { "some_scope", "some_other_scope" }
var analyzer = new StandardAccessTokenAnalyzer(authServerPublicKey, resourceServerPrivateKey);
var resourceServer = new DotNetOpenAuth.OAuth2.ResourceServer(analyzer);
var wrappedRequest = System.Web.HttpRequestWrapper(HttpContext.Current.Request);
var principal = resourceServer.GetPrincipal(wrappedRequest, scopes);
if (principal != null) {
// We've verified that the OAuth2 access token grants this principal
// access to the requested scope.
}
So, assuming I'm on the right track, what I need to do is to run that code somewhere in the ServiceStack request pipeline, to verify that the Authorization header in the API request represents a valid principal who has granted access to the requested scope.
I'm starting to think the most logical place to implement this is in a custom attribute that I use to decorate my ServiceStack service implementations:
using ServiceStack.ServiceInterface;
using SpotAuth.Common.ServiceModel;
namespace SpotAuth.ResourceServer.Services {
[RequireScope("hello")]
public class HelloService : Service {
public object Any(Hello request) {
return new HelloResponse { Result = "Hello, " + request.Name };
}
}
}
This approach would also allow specifying the scope(s) required for each service method. However, that seems to run rather contrary to the 'pluggable' principle behind OAuth2, and to the extensibility hooks built in to ServiceStack's AuthProvider model.
In other words - I'm worried I'm banging in a nail with a shoe because I can't find a hammer...
OK, after a lot of stepping through the various libraries with a debugger, I think you do it like this: https://github.com/dylanbeattie/OAuthStack
There's two key integration points. First, a custom filter attribute that's used on the server to decorate the resource endpoints that should be secured with OAuth2 authorization:
/// <summary>Restrict this service to clients with a valid OAuth2 access
/// token granting access to the specified scopes.</summary>
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, Inherited = true)]
public class RequireOAuth2ScopeAttribute : RequestFilterAttribute {
private readonly string[] oauth2Scopes;
public RequireOAuth2ScopeAttribute(params string[] oauth2Scopes) {
this.oauth2Scopes = oauth2Scopes;
}
public override void Execute(IHttpRequest request, IHttpResponse response, object requestDto) {
try {
var authServerKeys = AppHostBase.Instance.Container.ResolveNamed<ICryptoKeyPair>("authServer");
var dataServerKeys = AppHostBase.Instance.Container.ResolveNamed<ICryptoKeyPair>("dataServer");
var tokenAnalyzer = new StandardAccessTokenAnalyzer(authServerKeys.PublicSigningKey, dataServerKeys.PrivateEncryptionKey);
var oauth2ResourceServer = new DotNetOpenAuth.OAuth2.ResourceServer(tokenAnalyzer);
var wrappedRequest = new HttpRequestWrapper((HttpRequest)request.OriginalRequest);
HttpContext.Current.User = oauth2ResourceServer.GetPrincipal(wrappedRequest, oauth2Scopes);
} catch (ProtocolFaultResponseException x) {
// see the GitHub project for detailed error-handling code
throw;
}
}
}
Second, this is how you hook into the ServiceStack HTTP client pipeline and use DotNetOpenAuth to add the OAuth2 Authorization: Bearer {key} token to the outgoing request:
// Create the ServiceStack API client and the request DTO
var apiClient = new JsonServiceClient("http://api.mysite.com/");
var apiRequestDto = new Shortlists { Name = "dylan" };
// Wire up the ServiceStack client filter so that DotNetOpenAuth can
// add the authorization header before the request is sent
// to the API server
apiClient.LocalHttpWebRequestFilter = request => {
// This is the magic line that makes all the client-side magic work :)
ClientBase.AuthorizeRequest(request, accessTokenTextBox.Text);
}
// Send the API request and dump the response to our output TextBox
var helloResponseDto = apiClient.Get(apiRequestDto);
Console.WriteLine(helloResponseDto.Result);
Authorized requests will succeed; requests with a missing token, expired token or insufficient scope will raise a WebServiceException
This is still very much proof-of-concept stuff, but seems to work pretty well. I'd welcome feedback from anyone who knows ServiceStack or DotNetOpenAuth better than I do.
Update
On further reflection, your initial thought, to create a RequiredScope attribute would be a cleaner way to go. Adding it to the ServiceStack pipeline is as easy as adding the IHasRequestFilter interface, implementing a custom request filter, as documented here: https://github.com/ServiceStack/ServiceStack/wiki/Filter-attributes
public class RequireScopeAttribute : Attribute, IHasRequestFilter {
public void RequireScope(IHttpRequest req, IHttpResponse res, object requestDto)
{
//This code is executed before the service
//Close the request if user lacks required scope
}
...
}
Then decorate your DTO's or Services as you've outlined:
using ServiceStack.ServiceInterface;
using SpotAuth.Common.ServiceModel;
namespace SpotAuth.ResourceServer.Services {
[RequireScope("hello")]
public class HelloService : Service {
public object Any(Hello request) {
return new HelloResponse { Result = "Hello, " + request.Name };
}
}
}
Your RequireScope custom filter would be almost identical to ServiceStack's RequiredRoleAttribute implementation., so use it as a starting point to code from.
Alternately, you could map scope to permission. Then decorate your DTO or service accordingly (see SS wiki for details) for example:
[Authenticate]
[RequiredPermission("Hello")]
public class HelloService : Service {
public object Any(Hello request) {
return new HelloResponse { Result = "Hello, " + request.Name };
}
}
Normally ServiceStack calls the method bool HasPermission(string permission) in IAuthSession. This method checks if the list List Permissions in IAuthSession contains the required permission, so, in a custom IAuthSession you could override HasPermission and put your OAuth2 scopes checking there.
I have incorporate security into my wcf service using wif. Below my high level design.
Wif sts application - Here i have used custom username security token handler for validate the usename & passsword
Wcf service - list of services
Web application -> where i consumed the wcf service.
STS custom username security token handler as follows:
public class CustomUserNameSecurityTokenHandler : UserNameSecurityTokenHandler
{
public override Microsoft.IdentityModel.Claims.ClaimsIdentityCollection ValidateToken(System.IdentityModel.Tokens.SecurityToken token)
{
UserNameSecurityToken userNameToken = token as UserNameSecurityToken;
CredentialStore.AuthenticateUser(userNameToken.username, userNameToken.Password);
// ...
}
}
Code to consume the wcf service from web application
ClientCredentials oldCredentials = client.Endpoint.Behaviors.Remove<ClientCredentials>();
CachedClientCredentials newCredentials = new CachedClientCredentials(_tokenCache, oldCredentials);
client.Endpoint.Behaviors.Add(newCredentials);
client.ClientCredentials.UserName.UserName = "Admin"
client.ClientCredentials.UserName.Password = "password";
client.Authenticate();
While consume the wcf service i am able to send the username and password to STS validateToken method for authenticate and my scenario is like i want to send one more value (current web site address) to validatetoken method from consume part. i have workaround to send the additional value part of username but that is not the good idea to do that.
So could you please help me to resolve my issue?
An STS service that I have implemented requires a ClientID in addition to the username and password. I've solved this problem by adding custom elements into the security token request when initialising the service client. The STS service then reads out these values whilst authorizing the token and also passes back the ClientID in the claims.
// init client..
_serviceClient.ClientCredentials.UserName.UserName = Username;
_serviceClient.ClientCredentials.UserName.Password = Password;
var doc = new XmlDocument();
XmlElement customElement = doc.CreateElement("ExtraAuthData", Name, "http://localhost/STS/identity");
customElement.InnerText = Value;
(_serviceClient.Endpoint.Binding as WS2007FederationHttpBinding).Security.Message.TokenRequestParameters.Add(customElement);
Not sure if this is a recommended approach or not, I couldn't find any other way of doing this.