SID from ZUMO Login (MobileServiceUser) differs from the users' ObjectId - xamarin.forms

I am working on a Xamarin.Forms based crossplatform app targetting iOS and Android. My backend is an ASP.NET Webapplication hosted as an Azure App Service and users can register accounts that I manage with Azure Active Directory B2C. For authentication, I use MSAL 4.0 and the client application communicates with the backend using the MobileServiceClient library.
Because the users' data has relationships, I chose to let the controllers' put methods add the users' SIDs automatically and filter requested data on that SID, because this identifier is available after authorization though the users IClaimsPrincipal anyway.
However, I don't understand the origins of these SIDs because I cannot find them anywhere else.
This is what I can tell so far:
Within Azure ADB2C, I have two registered users. One of them (UserA) came in using Facebook as IdentityProvider, the other (UserB) Microsoft.
UserA has the Object Id FFC1*** on ADB2C.
UserB has the Object Id E990*** on ADB2C.
Both have the same name, but different registered email addresses.
This is how I instantiate the MSAL client:
public static IPublicClientApplication PCA = null;
...
PCA = PublicClientApplicationBuilder.Create(ClientID)
.WithRedirectUri($"msal{ClientID}://auth")
.WithB2CAuthority(Authority)
.WithIosKeychainSecurityGroup("com.microsoft.msalrocks")
.Build();
ClientId refers to Azure Active Directory B2C > Applications > Application > Application Id
Authority resolves to something like https://application.b2clogin.com/tfp/application.onmicrosoft.com/B2C_1_SignInSignUp
The policy configuration (user flow) on B2C is configured to include the following claims:
Given Name
Identity Provider
User's Object Id
I log in using MSAL this way:
var accounts = await App.PCA.GetAccountsAsync();
var result = await App.PCA.AcquireTokenSilent(
App.Scopes,
accounts.FirstOrDefault())
.WithB2CAuthority(App.Authority)
.ExecuteAsync();
App.Scopes resolves to
public static string[] Scopes = {
"https://application.onmicrosoft.com/api/user_impersonation",
"https://application.onmicrosoft.com/api/offline_access"};
At this point, I have an AuthenticationResult which I could extract valuable information from such as the users' given name or the Object Id which equals the Object Id I can also see in the user management pane in my Azure B2C directory:
JObject authenticatedUser = AuthenticationHelper.ParseIdToken(result.IdToken);
var objectId = authenticatedUser["sub"]?.ToString();
var username = authenticatedUser["given_name"]?.ToString();
The AuthenticationResult contains an IdToken and an AccessToken. They are almost identical with the AccessToken adding an scp attribute containing scopes. In my case it contains "user_impersonation".
Now with the user being authenticated against ADB2C, I need my app to also forward the authentication to ZUMO, that is, the MobileServiceClient, so that the user can make authorized calls against my backends' controllers.
For this, I need the resturned AccessToken (which I can also extract from the above AuthenticationResult), wrap it into a JObject and finally transmit it to the MobileServiceClient like this:
MobileServiceClient client;
client = new MobileServiceClient("https://application.azurewebsites.net");
var zumoPayload = new JObject()
{
["access_token"] = result.AccessToken
};
await client.LoginAsync(MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory, zumoPayload);
Now that the MobileServiceClient has an authenticated user, every future httprequest will contain respective information that the controllers' [authorize] attribute satisfy.
HOWEVER.
This is when it becomes strange.
When the MobileServiceClient is instantiated and its LoginAsync method called using the ZumoPayload from above, the resulting MobileServiceUser is being populated with two properties:
MobileServiceAuthenticationToken and
UserId
The funny thing is, that this token looks very different from the IdToken or AccessToken I received when authenticating with MSAL, but what bugs me even more is that the User Id is even something totally different!
There is a sub attribute included containing something like sid:956b*** for UserA and sid:e358*** for UserB which clearly differ from the above Object Ids.
Can anyone explain to me where these SIDs come from?

Related

Getting user claims through jaggery for API Manager

I have a requirement to get user claims of a user logged into API Manager. I would prefer to do this using jaggery.
However, when I try the following
var carbon = require('carbon');
var tenantId = -1234;
var url = 'https://10.100.0.49:9443/admin/services/';
var server = new carbon.server.Server(url);
var userManager = new carbon.user.UserManager(server, tenantId);
var user1 = new carbon.user.User(userManager, 'admin');
var userClaims = user1.getClaimsForSet(['http://wso2.org/claims/givenname'],'default');
print(userClaims);
I get {} as the response. I have added a value for givenname for admin through the management console
I have also tried to get the claim value for another user who signed up to the API Store but to no avail.
Apart from this, I created a js module within carbon.user, declared it in module.xml and called it through a jag file. Once again, I get a response but it's empty ie. {}. The service I linked through js was org.wso2.carbon.um.ws.service.UserStoreManagerService
I am actually using API Manager in conjunction with Identity Server. Both servers have been clustered according to the documentation given here
https://docs.wso2.com/display/CLUSTER44x/Configuring+the+Identity+Server+5.2.0+as+a+Key+Manager+with+API+Manager+2.0.0
and here
https://docs.wso2.com/display/CLUSTER44x/Configuring+the+Pre-Packaged+Identity+Server+5.2.0+with+API+Manager+2.0.0
Since the userstore is the same, I presume that even though the Identity Server is handling user management, I should be able to get the claims through API Manager.
However, just to be sure, I have also tried using API Manager as is and retrieving claims by the above method.
What could be the cause of this and how do I retrieve the claims I need?

Authorization by Role/Group in ASP.NET using Auth0

Thanks in advance for your help in this matter!
I was hoping someone could help me figure out how to authorize API access by Group assigned in the Auth0 Authorization extension.
I currently am using the [Authorize] attribute in the web api perfectly - it allows an api call if they have signed in successfully and blocks it if not.
However, if I try [Authorize(Roles = "myGroupName")] authorization fails. Same occurs if I add it to the users app_metadata manually in the Users dashboard on the Auth0 website instead of assigning through the extension.
My project is set up by following the Angular Quick Start and Asp.Net Quick Start. My webapiconfig where I validate the token server side is:
class WebApiConfig
{
public static void Register(HttpConfiguration configuration)
{
var clientID = WebConfigurationManager.AppSettings["auth0:ClientId"];
var clientSecret = WebConfigurationManager.AppSettings["auth0:ClientSecret"];
configuration.MessageHandlers.Add(new JsonWebTokenValidationHandler()
{
Audience = clientID,
SymmetricKey = clientSecret
});
configuration.Routes.MapHttpRoute("API Default", "api/{controller}/{id}",
new { id = RouteParameter.Optional });
}
}
The Auth0 Authorization extension currently supports authorization decisions through the concept of groups. You can create a group, assign users to that group and that configure an application to only be accessible to user within a specific group. All of this would be handled automatically and any user outside of the application expected groups would be denied complete access.
Your use case is a bit different, but valid nonetheless. You want the groups configured with the extension to be sent along the generated token so that the application itself makes authorization decisions based on those values.
In order for the groups configured within the extension to be sent along in the token, the first thing you need to do is request them. For this, you need to include the groups scope when performing the authentication requests.
Add the user's group membership to the outgoing token (which can be requested via the OpenID groups scope);
(emphasis is mine, source: Authorization Extension Docs, section Rule Behavior)
If you request a token using that scope and then decode it in jwt.io, you would get something similar to this (the actual groups would vary by user):
{
"groups": [
"GROUP-1",
"GROUP-2"
],
"iss": "https://[tenant].auth0.com/"
}
Now, for the validation of this information on the ASP .NET API side. Assuming the sample you're using is this one (ASP.NET Web API), the group information contained within the token would be mapped to the following claims:
Type: groups | Value: GROUP-1
Type: groups | Value: GROUP-2
This happens because of the logic that exists in the JsonWebToken class which handles arrays coming from the JWT payload by creating per-value claim that share the same type.
The final part is making sure the AuthorizeAttribute checks these claims of type groups instead of trying to lookup role claims. You should be able to accomplish this, by changing the RoleClaimType constant in the JsonWebToken class to have the value "groups" instead of "http://schemas.microsoft.com/ws/2008/06/identity/claims/role".
Like you certrainly know, the Authorize attribute works using what is in the principal: something that inherits IPrincipal.
In web api, it is even more specific; it is something that inherits ClaimsPrincipal (this implements himself IPrincipal).
As you certainly know already, a claim is like a key-value pair.
The ClaimsPrincipal contains a serie of key-value pairs that are directly taken from the authentication token. This authentication token is issued by the authentication server most of time as JWT (Json Web Token). Most of time as well, the authentication server is using OAuth, like is your case.
If the user group, that you expect to be the role in your application doesn't work by using the out-of-the-box Authorize attribute, it's because it is not mapped correctly: Auhtorize checks the claim with claim type: http://schemas.microsoft.com/ws/2008/06/identity/claims/role (the "claim type" is the "key" of the key-value pair). That means that if you want your Authorize to work, this claim must be valued with the group.
You can do several things to have a clean authorization in your application.
Make a custom Authorize attribute. This Authorize attribute would check the role using a different claim type. The claim type that refers to the user group depends on your authentication server. If you don't find what claim type is used for groups in the doc of your authentication server, run your application in debug, and check every claim that is contained in the property User of your controller. You will certainly find what the claim type you are interested in.
Change the setup of your authorization server by redefining the mapping between user information and claims of the token that is produced (in your case, map groups of the user to the claim that has the type http://schemas.microsoft.com/ws/2008/06/identity/claims/role). Generally, this can be setup per client application or even globally. For example this is the way that must be done if you use an ADFS authentication, AzureAD or WSO2 authentication server (http://wso2.com/products/identity-server/)
Add an owin middleware to modify the current principal. It will change the current principal by copying the value of the claim that contains groups into the claim type http://schemas.microsoft.com/ws/2008/06/identity/claims/role. This middleware must be inserted in the flow after the authentication middleware
I have no rights to comment so I'm going to inquire from here. Why are you doing this
[Authorize(Roles = "myGroupName")]
as far as I remember when I was implementing group based authorization I was still typing
[Authorize(Roles = "myRoleName")]
Not other way around.

Use Firebase.com authenication without forcing the user to create an account

I am developing a small App to allow the user to store To-Do items. I am using Firebase ass my backend.
For the first iteration I don't want the user to have to sign-up, but still only see it's own data. My first thought was just to use the anonymous authentication, store the UID an reuse it everytime the app is started. This is not possible since the session is gonna time out at some point and the user would get a new UID the next time.
I of course want to make sure that a user can only see it's own items using the Firebase Security & Rules.
The idea would be to save the items like this: app.firebase.com/user/123456/todo-item
123456 beeing the unique ID of the user.
Can I create a unique identifier myself and still use the Firebase Security & Rules?
You would have to run your own custom authentication solution.
When the Activity loads, you'll have to make a request to your server. Then on the server you can create tokens for a user when they load the page:
// These payload properties are accessible
// by Security Rules which is awesome
Map<String, Object> payload = new HashMap<String, Object>();
payload.put("uid", "uniqueId1");
payload.put("some", "arbitrary");
payload.put("data", "here");
TokenGenerator tokenGenerator = new TokenGenerator("<YOUR_FIREBASE_SECRET>");
String token = tokenGenerator.createToken(payload);
There's more packages than just Java, so read the docs.
Then when you deliver the token back to the user, you would need to store the token locally.
Once the token is stored, you can retrieve it and authenticate.
Firebase ref = new Firebase("https://<YOUR-FIREBASE-APP>.firebaseio.com/");
ref.authWithCustomToken(AUTH_TOKEN, new Firebase.AuthResultHandler() {
#Override
public void onAuthenticationError(FirebaseError error) {
System.err.println("Login Failed! " + error.getMessage());
}
#Override
public void onAuthenticated(AuthData authData) {
// authenticated
}
});
You probably aren't thrilled about having to run a server, but take a look at using Google AppEngine with the Firebase JVM client. It's pretty easy and handles the server maintenance for you.
This tutorial by a former Google Cloud tools member, and current Firebase team member is a great place to start.

Implement Office 365 styled Basic Authentication (Active Profile)

I'm working on a SaaS application built around ASP.net MVC & WebAPI and want to make it easy for enterprises to use my service. Example would be Office 365 Basic Authentication (Active Profile) where the user enters his username/password on microsoft's site (or desktop app) and he is authenticated against his employer's Active Directory. My understanding so far is that I would need to create a RP-STS which will accept credentials and then forward those to AD FS Proxy running on the client company's AD server. Is this correct?
If yes, then how do I implement this? Setting up AD server adding a Relying Party and AD FS Proxy Role is easy, so that's really not an issue. I just need to figure out how to create/setup RP-STS service and any other steps involved in this process. There just isn't an example/tutorial of this in .net
I believe this msdn blog post describes exactly what you're asking for. It has a complete walkthrough of the entire process, including creating an RP by creating a normal WCF service, and then use the provided utility to configure the service to trust your ADFS.
http://blogs.msdn.com/b/mcsuksoldev/archive/2011/08/17/federated-security-how-to-setup-and-call-a-wcf-service-secured-by-adfs-2-0.aspx
Edit:
This code, taken from the linked article (comments are mine), is a demonstration of active federation. The client application is manually retrieving a security token from the ADFS. Passive Federation would involve forwarding the user to a secure web page in which they could send their credentials directly to the ADFS. The major benefit of Passive Federation is that the end user's secret credentials are provided directly to the ADFS, and the RP's client side code never has access to it.
var requestTokenResponse = new RequestSecurityTokenResponse();
//The line below is the 'Active' federation
var token = Token.GetToken(#"mydomain\testuser", "p#ssw0rd", "http://services.testdomain.dev/wcfservice/Service.svc", out requestTokenResponse);
var wcfClient = new FederatedWCFClient<MyTestService.IService>(token, "WS2007FederationHttpBinding_IService"); // This must match the app.config
var client = wcfClient.Client as MyTestService.IService;
var result = client.GetData();
Console.WriteLine(result);
wcfClient.Close();
Take a look at these links:
https://github.com/OfficeDev/O365-WebApp-SingleTenant
https://github.com/OfficeDev/O365-WebApp-MultiTenant
It shows how to make an application using the office 365 api to authenticate and authorize the users.
Be aware about Single Tenant and Mult Tentant application, and choose the right one.
It's really easy to do that, I've done it couple months ago.
I found the answer on the blog: http://leandrob.com/2012/04/requesting-a-token-from-adfs-2-0-using-ws-trust-with-username-and-password/
What this code essentially does is that it directly authenticates with the tenant's ADFS endpoint and gets a token as well. That's what I was looking for.
var stsEndpoint = "https://[server]/adfs/services/trust/13/UsernameMixed";
var relayPartyUri = "https://localhost:8080/WebApp";
var factory = new WSTrustChannelFactory(
new UserNameWSTrustBinding(SecurityMode.TransportWithMessageCredential),
new EndpointAddress(stsEndpoint));
factory.TrustVersion = TrustVersion.WSTrust13;
// Username and Password here...
factory.Credentials.UserName.UserName = user;
factory.Credentials.UserName.Password = password;
var rst = new RequestSecurityToken
{
RequestType = RequestTypes.Issue,
AppliesTo = new EndpointAddress(relayPartyUri),
KeyType = KeyTypes.Bearer,
};
var channel = factory.CreateChannel();
SecurityToken token = channel.Issue(rst);
Another good article on that blog is: http://leandrob.com/2012/02/request-a-token-from-adfs-using-ws-trust-from-ios-objective-c-iphone-ipad-android-java-node-js-or-any-platform-or-language/ - which covers other similar scenarios.

MVC 5 and use of claims default authentication

I have a question regarding the claims in MVC 5.
So basically imagine I have a registered user in DB, now the user is going to log in, like so:
private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
AuthenticationManager.SignOut(DefaultAuthenticationTypes.ExternalCookie);
var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);
// Add more custom claims here if you want. Eg HomeTown can be a claim for the User
var homeclaim = new Claim(ClaimTypes.Country, user.HomeTown);
identity.AddClaim(homeclaim);
AuthenticationManager.SignIn(new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}
So in this case i add a new claim to the identity and then i sign in this identity.
Now my questions are:
What is the use of setting this claim? (because i can also get this from the db if i need it, what is the point in this case of claim)
And how do i use it later on in the code?
Setting the Claim against the identity makes your application security more efficient and saves hitting your database each time.
The method above can be known as a Claims Transformation which often involves reading in data that is transformed into claims after authentication succeeds.
In order to read it later you can do this:
//Get the current claims principal
var identity = (ClaimsPrincipal)Thread.CurrentPrincipal;
//Get the country from the claims
var country = identity.Claims.Where(c => c.Type == ClaimTypes.Country).Select(c => c.Value);
Update
Just to provide some further information to the answer as discussed in the comments below.
With a Claims based approach you also benefit from being able to use a claims authorization manager which can provide a centralized/finely grained access control to resources and actions. 
If you've not used claims before it's best to think of actions against resources rather than role based permissions. That way you can drill right down and control access to each resource/action individually rather than having a multitude of roles for each one. 
I personally like to use a mixture but store the roles as claims too. 
That way I can use the standard authorization tags in mvc with roles, which read the claims and use thinktecture's attributes/ClaimsAuthorization to make the claims authorization manager pickup the more complicated rules.
A good link on implementing claims based authentication in MVC 4 is available here:
http://dotnetcodr.com/2013/02/25/claims-based-authentication-in-mvc4-with-net4-5-c-part-1-claims-transformation/

Resources