Utilize JWTBearer from multiple Identity Providers in ServiceStack API - servicestack

Is it possible for a ServiceStack api to accept jwt tokens from multiple identity providers?
I have one admin application that will be calling all our apis across environments. I need to allow my api's to accept jwt tokens from two different identity providers. This can be accomplished in web api, by calling the .AddJwtBearer help method twice and not providing a default schema in the AddAuthentication() helper. And the providing both in the AddAuthorization helper method. I tested this out in ServiceStack and it is not working for me.
This is in the .net core startup, configure services.
services.AddAuthentication()
.AddJwtBearer("Bearer", options => {
options.Authority = Configuration["IDENTITYSRV_WEB_BASEURL"];
options.RequireHttpsMetadata = Boolean.Parse(Configuration["IDENTITY_HTTPSMETADATA"]);
options.Audience = Configuration["IDENTITY_VALIDAUDIENCE"];
})
.AddJwtBearer("Admin", options =>
{
options.Authority = "Configuration["IDENTITYSRV_WEB2_BASEURL"]";
options.RequireHttpsMetadata = Boolean.Parse(Configuration["IDENTITY_HTTPSMETADATA"]);
options.Audience = Configuration["IDENTITY_VALIDAUDIENCE"];
});
AppHost
AuthFeature auth = new AuthFeature(() => new AuthUserSession(), new IAuthProvider[] { new NetCoreIdentityAuthProvider(AppSettings), })
{
IncludeAssignRoleServices = false,
IncludeRegistrationService = false,
IncludeAuthMetadataProvider = false
};
Plugins.Add(auth);
Any suggestions or work around?

ServiceStack's JWT Auth Provider supports all HMAC and RSA crypto algorithms for its JWT or JWE tokens, but it can only be configured with the 1 algorithm you want it to use. So it's technically not possible for it to verify JWT Tokens from different authorities which would likely be configured with different keys and algorithms.
The next obstacle is that if all Identity providers were configured to use the same Key and Algorithm, they would need to encode the same contents ServiceStack uses in order for the JWT to be correctly deserialized into an Authenticated ServiceStack Session. Most of the names used in ServiceStack's JWT's have well-known names however there are others that don't like roles and perms, in which case ServiceStack JWT's have adopted the Azure Active Directory Conventions. Although there is an opportunity to apply custom logic when inspecting the verified JWT Body and populating the Session using the PopulateSessionFilter.
Ultimately I don't think trying to funnel multiple JWT's into the same implementation is a viable strategy, instead I would be looking at creating Custom JWT Auth Providers like JwtAuthProviderReader.cs which just knows how to handle parsing JWT's from a single provider which would then know how to verify & extract the Authenticated Session Info from each JWT and use it to populate a ServiceStack Session. This could be done in a "single uber JWT Auth Provider" that has knowledge in being able to parse every JWT sent to it, but as JWT Tokens are sent with the same Authorization: Bearer {Token} HTTP Header there would need to be some information in the JWT Headers that determines which crypto algorithms it should use to validate each token. If all Identity Providers use different alg then that might be enough to be able to distinguish the identity provider.
Either way there's no pre-built solution in ServiceStack that you could configure to support multiple identity Auth Providers, the other approach you may want to look at is to maintain all Authentication in a central Identity Server Auth Provider so then your Websites only need to be configured to support Authentication from the central Identity Server.

Related

JWT authentication with two different services

We have a service architecture that currently only supports client authentication. A Java service based on spring boot and spring security issues long lived JWT based on tenants for other services to authenticate against each other. For example a render service needs to get templates from the template service.
We now want to build a user service with node.js that issues short lived tokens for users to also access some of those services and only access the resource visible to the user. For example the user wants to see only their templates in a list.
My question is: what do I need to watch out for when implementing the /auth resource on the user service? I have managed to issue a JWT with the required information and obviously the same secret in the user service to access the template service. But I'm not sure if it is secure enough. I had to add a random JID to the user JWT to get it accepted by the template service (which is also implemented with spring boot).
Is there a security issue I need to watch out for? Is this approach naiive?
This is my javascript code that issues the JWT:
const jwt = require('jwt-simple');
const secret = require('../config').jwtSecret;
const jti = require('../config').jti;
// payload contains userId and roles the user has
const encode = ({ payload, expiresInMinutes, tenantId}) => {
const now = new Date();
payload.jti = jti; // this is a UUID - spring security will otherwise not accept the JWT
payload.client_id = tenantId; // this is required by the template service which supports tenants identified through their clientId
const expiresAt = new Date(now.getTime() + expiresInMinutes * 60000);
payload.expiresAt = expiresAt;
return jwt.encode(payload, secret);
};
I think of adding some type information to the user JWT so that those java services that do not allow any User access can directly deny access for all user JWTs. Or maybe I can use the JTI here? Will research how spring boot handles that. I'll probably also have to add #Secured with a role distinction to all the services that allow user access to only some resources.
But those are technical details. My concern really is that I am unsure about wether the entire concept of using JWTs issued from different sources is secure enough or what I have to do in the user service to make it so.
Yeah your concept is right since you are the owner of jwt that means only you can write the jwt, others can read it but can not modify it.
So your userservice will create the token with certain information like userid and another service will decode that jwt fetch userid and validate that userid

ServiceStack OAuth2 mobile native authentication

I need to log on through OAuth 2 how can I do that without using WebView in Android?
Thanks.
In the latest v4.5.7 of ServiceStack you'll be able to login into Twitter, Facebook or Github using their SDKs and previous saved access tokens.
Authentication via AccessToken is also made available to OAuth2 providers in the same way where you can authenticate directly by adding the AccessToken to the Authenticate Request DTO, e.g:
var request = new Authenticate
{
provider = "GoogleOAuth",
AccessToken = GoogleOAuthAccessToken,
};
var response = client.Post(request);
response.PrintDump();
Although you will first need to retrieve the AccessToken which typically requires opening a WebView to capture Users consent.
For other OAuth2 providers other than Google Auth you will need to provide an implementation of VerifyAccessToken that returns a boolean that determines whether the AccessToken is valid or not, e.g:
new MyOAuth2Provider {
VerifyAccessToken = accessToken => MyValidate(ConsumerKey,accessToken),
}
This is different for each OAuth provider where some don't provide an API that lets you determine whether the AccessToken is valid with your App or not.

Shiro: where credential should be stored?

Little prehistory:
I develop RESTful services. That services receives requests from the web frontend and resends it to another server with the actual business logic. I use Shiro to protect my services. Problem is that some business logic functions require a user password. Of course, I can store password in my principal, but I think it is not correct to store credentials there.
Question
So, what is the conceptual right place where I should store credentials to have access inside my REST services?
Update
Ok, I can also store passwords in Shiro sessions, but i don't think that it is the correct place.
Normally, the info is kept in an implementation of AuthenticationToken. This interface has two method: getPrincipal (for example login or email) and getCredentials(). The last is usually used to store a password.
If you look at class UsernamePasswordToken, which is an implementation of this interface, you see that the two are indeed used for username and password.
Now what we did is extend the class AuthorizingRealm for our own authentication mechanism and in the authentication method we store the token in the principal.
#Override
public AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) {
... authentication logic
SimplePrincipalCollection principalCollection = new SimplePrincipalCollection(login, realmName);
principalCollection.add(token, realmName);
SimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(principalCollection, login.getPasswordHash());
return simpleAuthenticationInfo;
}
Now you can get the token later:
PrincipalCollection principals = SecurityUtils.getSubject().getPrincipals();
AuthenticationToken token = principals.oneByType(AuthenticationToken.class);

Web API 2 OWIN Bearer Token purpose of cookie?

I am trying to understand the new OWIN Bearer Token authentication process in the Single Page App template in MVC 5. Please correct me if I'm wrong, for the OAuth password client authentication flow, Bearer Token authentication works by checking the http authorization request header for the Bearer access token code to see if a request is authenticated, it doesn't rely on cookie to check if a particular request is authenticated.
According to this post:
OWIN Bearer Token Authentication with Web API Sample
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
using (IdentityManager identityManager = _identityManagerFactory.CreateStoreManager())
{
if (!await identityManager.Passwords.CheckPasswordAsync(context.UserName, context.Password))
{
context.SetError("invalid_grant", "The user name or password is incorrect.");
return;
}
string userId = await identityManager.Logins.GetUserIdForLocalLoginAsync(context.UserName);
IEnumerable<Claim> claims = await GetClaimsAsync(identityManager, userId);
ClaimsIdentity oAuthIdentity = CreateIdentity(identityManager, claims,
context.Options.AuthenticationType);
ClaimsIdentity cookiesIdentity = CreateIdentity(identityManager, claims,
_cookieOptions.AuthenticationType);
AuthenticationProperties properties = await CreatePropertiesAsync(identityManager, userId);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(cookiesIdentity);
}
}
The GrantReourceOwnerCredentials function not only compose the ticket with this line: context.Validated(ticket); but it also compose a cookie identity and set it to the cookie with this line: context.Request.Context.Authentication.SignIn(cookiesIdentity);
So my questions are, what is the exact purpose of the cookie in this function? Shouldn't the AuthenticationTicket be good enough for authentication purpose?
In the SPA template there are actually two separate authentication mechanisms enabled- cookie authentication and token authentication. This enables authentication of both MVC and Web API controller actions, but requires some additional setup.
If you look in the WebApiConfig.Register method you'll see this line of code:
config.SuppressDefaultHostAuthentication();
That tells Web API to ignore cookie authentication, which avoids a host of problems which are explained in the link you posted in your question:
"...the SPA template enables application cookie middleware as active mode as well in order to enable other scenarios like MVC authentication. So Web API will still be authenticated if the request has session cookie but without a bearer token. That’s probably not what you want as you would be venerable to CSRF attacks for your APIs. Another negative impact is that if request is unauthorized, both middleware components will apply challenges to it. The cookie middleware will alter the 401 response to a 302 to redirect to the login page. That is also not what you want in a Web API request."
So now with the call to config.SuppressDefaultHostAuthentication() Web API calls that require authorization will ignore the cookie that is automatically sent along with the request and look for an Authorization header that begins with "Bearer". MVC controllers will continue to use cookie authentication and are ignorant of the token authentication mechanism as it's not a very good fit for web page authentication to begin with.
The existence of the cookie also left me puzzled, since it clearly is not necessary in a bearer token authentication scenario... In this post the author dissects the individual accounts template, and has the following to say about the cookie:
The method also sets an application cookie. I don’t see a good reason for that.
My guess is that the authors of the template wanted to show examples of different kinds of authentication logic, and in this particular case they wanted to show how the authentication information could be stored in both the bearer token authentication JSON payload, as well as in a standard authentication cookie.
The fact that the JSON authentication payload is set to also include an additional (unnecessary) unencrypted property (the user id), in addition to the encrypted ticket, seems to support this theory:
var properties = CreateProperties(user.UserName);
var ticket = new AuthenticationTicket(oAuthIdentity, properties);
It seems that the authors of the template wanted to provide some useful examples, rather than the bare minimum needed to achieve bearer token authentication. This is also mentioned in the linked post above.
The cookie has one important purpose. Its value contains the bearer token which can be extracted by client-side javascript on your pages. This means that if the user hits F5 or refreshes the page, the cookie will typically persist. Your client-side javascript can then grab the bearer token from the cookie when the page reloads.

Authorization extensions for ServiceStack

Is there any (or going to be any) built in support for declaratively securing (i.e. using attributes) REST services for oAuth2?
I would like to specify that the REST services of my SS web service can only be accessed by a client if they specify the oAuth2 'Authorization' header in their request to the service.
I don't want my service to provide authentication to my clients (i.e. no AuthFeature). Clients need to have already done authentication with a oAuth service (i.e. facebook etc.).
Using the [Authenticate] attribute on your Service ensures that only authenticated clients have access.
The Authentication wiki explains how to initialize ServiceStack's built-in AuthFeature to specify only the providers you want to allow clients to authenticate with, e.g. You can ensure clients can only Authenticate with either LinkedIn or Google OAuth2 providers with:
var appSettings = new AppSettings(); //Access Web.Config AppSettings
Plugins.Add(new AuthFeature(() => new CustomUserSession(),
new IAuthProvider[] {
new GoogleOAuth2Provider(appSettings), //Sign-in with Goolge OAuth2
new LinkedInOAuth2Provider(appSettings), //Sign-in with LinkedIn OAuth2
}));
Note: OAuth2 requires the additional ServiceStack.Authentication.OAuth2 NuGet package and Web.Config settings, see Auth docs for more info.
Using Request Filters
You can also enforce specific requirements for client requests by a Global Request Filter or opt-in Request Filter Attributes, e.g:
this.RequestFilters.Add((httpReq, httpRes, requestDto) => {
var authHeader = httpReq.Headers[HttpHeaders.Authorization];
if (!IsValidAuthHeader(authHeader)) {
httpRes.StatusCode = (int)HttpStatusCode.Unauthorized;
httpRes.StatusDescription = "Authentication is required";
httpRes.EndRequest();
}
});
More Service Restrictions
Also related are the Security docs describes how you can declaratively restrict services using the [Restrict] attribute.

Resources