User Managed Identity - how to authenticate using c# - azure-managed-identity

Is there an example of how to authenticate azure resource using User Managed Identity using c#? I am using the following code to authenticate using system managed identity and it works fine. but not sure about how to pass the user managed identity resource in the following example.
AzureServiceTokenProvider azureServiceTokenProvider = new AzureServiceTokenProvider();
KeyVaultClient keyVaultClient = new KeyVaultClient(new KeyVaultClient.AuthenticationCallback(azureServiceTokenProvider.KeyVaultTokenCallback));
var secret = await keyVaultClient.GetSecretAsync("https://mykeyvaultname.vault.azure.net/secrets/test")
.ConfigureAwait(false);
return new string[] { secret.Value };

Please see the documentation here. This feature is in the 1.2.0-preview version of the library. It only works on Azure VMs and VMSS as of now. You need to set the client id in a connection string, which can either be specified in the constructor or in the env variable (documentation of other connection string options here). In this scenario, the constructor is recommended, so you can use developer identity/ cert for local and switch to the user-assigned identity on Azure.
Update: The library has been updated to support user assigned identity in App Services as well as part of 1.2.0-preview2.

Related

Authenticating with Azure Active Directory: RoleProvider for ClaimsIdentity?

Fellow developers, I'm updating an IIS web application from using Windows Authentication to using Azure Active Directory instead. The setup looks fine: I can successfully authenticate, and I get the user's identity as a ClaimsIdentity.
However, this does not mesh well with my current use of System.Web.Security.WindowsTokenRoleProvider. When doing an IsInRole() check, the role provider detects that the current identity is not a WindowsIdentity and throws a ProviderException:
Method is only supported if the user name parameter matches the user name in the current Windows Identity.
I believe I need to configure the application's role manager to use a ClaimsIdentity-friendly provider. Is there a standard role provider class that plays well with the ClaimsIdentity, or will I need to build a custom role provider?
Edit: I've built my own custom role manager that appears to only need an implementation of GetRolesForUser(string username) method. It solves my problem, but doesn't answer my question :)
The base class of Claims Identity is the System.Security.Claims namespace. Hence it needs to be used in the project.
using System.Security.Claims;
To achieve this, we need to use customize the ClaimsIdentity based on our requirement as shown below.
Below is the code snippet:
string Default_IdentityProvider_ClaimValue = "Some_ClaimsIdentity";
var id = new ClaimsIdentity(DefaultAuthenticationTypes.ApplicationCookie, ClaimsIdentity.DefaultNameClaimType, ClaimsIdentity.DefaultRoleClaimType);
id.AddClaim(new Claim(ClaimTypes.NameIdentifier, users.UserId.ToString(), ClaimValueTypes.String));
id.AddClaim(new Claim(ClaimsIdentity.DefaultNameClaimType, users.UserName, ClaimValueTypes.String));
id.AddClaim(new Claim(Identity_Provider_ClaimType, Default_IdentityProvider_ClaimValue, ClaimValueTypes.String));
id.AddClaim(new Claim(ClaimsIdentity.DefaultRoleClaimType, users.UserName, ClaimValueTypes.String));```

Faking authentication during development

In my current asp.net MVC core application we use OpenId Connect to authenticate with our corporation's identity provider.
However during local development we cannot reach the the provider.
Also we would like to easily change claim values for development and unit testing purposes.
I tried swapping my service binding for IHttpContextAccessor to a DevelopmentHttpContextAccessor that fills up the HttpContext's Identity with the desired claims.
This is a bit of a roundabout way and it also doesn't work as the claims are emptied when I check them in my Service.
What is the standard way of handling this during development and unit testing? What am I missing?
The answer was not faking IHttpContextAccessor, but setting a custom ClaimsPrincipal to the identity property.
In your Startup.Configure you can add a middleware step:
app.Use((httpContext, nextMiddleware) => {
var claims = new[] {
// Your claims here
};
var claimsIdentity = new ClaimsIdentity(claims);
var user = new ClaimsPrincipal(claimsIdentity);
httpContext.User = user;
return nextMiddleware();
});

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?

Authenticate with ADFS inside Console App silently

I have a c# console application that references the ADAL.net library (Microsoft.IdentityModel.Clients.ActiveDirectory version 2.19.208020213)
The purpose of the console app is to consume a HTTP endpoint which is protected with ADFS.
The implementation of the ADFS auth is as follows....
var uc = new UserCredential("user", "password");
var ctx = new AuthenticationContext("https://sts.example.com/adfs", false);
var token = ctx.AcquireToken(ClientResourceUri, ClientId, uc);
The call to AcquireToken throws an exception...
This method overload is not supported by
'https://sts.example.com/adfs/'
Calling AcquireToken without the UserCredential object, and instead providing a redirectUri works, but throws up a dialog prompting for username and password, which is unsuitable as the console app will be executed in a non user environment...
var redirect = new Uri("https://example.com/arbitaryRedirect");
var token = ctx.AcquireToken(ClientResourceUri, ClientId, redirect);
//dialog is shown
If i switch to the latest alpha release of the adal.net library (3.6.212041202-alpha)
the error is more revealing...
MSIS9611: The authorization server does not support the requested
'grant_type'. The authorization server only supports
'authorization_code' or 'refresh_token' as the grant type.
However, mining google yields very little.
Is it actually possible to authenticate silently against ADFS?
Would i be correct in assuming (based upon answers in other posts) that the correct approach is to use WsTrustChannelFactory instead?
If not, what is the best approach?
It is possible using ADAL 3.x and ADFS in Windows Server 2016, with pretty much the same code you posted. Combinations of older versions of either ADAL or ADFS won't work.
Alternatively, you can use WS-Trust - which is significantly harder to handle, but can get the job done.

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.

Resources