I have been looking over examples of using Asp.Net Identity and various providers to supply authentication using facebook, twitter, etc.
I have an MVC 6 solution, currently being developed using VS2015 RC. It will be deployed to an organisational IIS. AD is primarily used to authenticate users, the majority of whom are authenticated via the domain, either within the local network or remotely.
However there is the possibility that some users will want access to the system over the internet, without having a domain account. or these users, the user will register, an admin will approve the account and assign roles and permissions locally within the application database.
The project team are requesting that users on the local network or otherwise authenticated on the domain do not need to logon.
AD is in use, but not ADFS to the best of my knowledge.
Is this even possible? I believe what I need is an OWIN provider for AD, but the Microsoft one seems to work with either ADFS or AAD.
Thanks.
You can definitely use Asp.Net Identity for the users that are registering over the internet.
You can also use Asp.Net Identity to sign-in the AD users using the below nuget package, but the windows users information (just the username, email) will need to be stored in your application database.
https://github.com/MohammadYounes/OWIN-MixedAuth
After you implement this nuget package, just do this to authenticate the windows user.
Add this method in ApplicationSignInManager class in IdentityConfig file and call this method if the windows user is logging in.
public async Task<SignInStatus> WindowsLoginAsync(string userName, string password, bool isPersistent)
{
var signInStatus = SignInStatus.Failure;
using (var context = new PrincipalContext(ContextType.Domain, <your_domain_name>))
{
var valid = context.ValidateCredentials(userName, password);
if (valid)
{
UserPrincipal userPrincipal = UserPrincipal.FindByIdentity(context, userName);
if (userPrincipal != null)
{
var loginInfo = new ExternalLoginInfo
{
Login = new UserLoginInfo("Windows", userPrincipal.Sid.ToString())
};
signInStatus = await ExternalSignInAsync(loginInfo, isPersistent);
return signInStatus;
}
}
}
return signInStatus;
}
This will basically use cookie authentication for windows and web users alike.
After the user is authenticated you will need to add the windows user in the database and also add a record in IdentityUserLogin table with LoginProvider as "Windows" and ProviderKey as the userPrincipal.Sid and then call SignInManager.SignInAsync to login the user.
Using this approach I believe the windows user can also login over the internet, which your organization might not like.
Hope this helps!
Related
I have an up and running .NET 5 Web-API with a Blazor Server Client in Production. I'd like to switch from Individual User Accounts to Azure AD using App Roles to authenticate specific Users in my Controllers. I found lots of Information regarding Webassembly but none for Blazor Server.
Has somebody a working Solution for a .NET 5/6 Web-Api with a Blazor Server Client and integrating Azure App Roles?
Apps are already registered in the Azure Portal and so forth, I just need to know how to pass the App Roles specific stuff to my API, so my Controller can work with the [Authorize("Admin")] stuff. I suspect it will use Bearer Tokens aswell.
Edit:
Thanks a lot for reading. So I figured out that if I use something like this in my Controller only using the [Authorize] Attribute without any roles:
var identities = HttpContext.User.Identities.ToList();
foreach (var item in identities)
{
if (item.RoleClaimType == "admin")
{
// return or do something
}
}
It would just work fine but there has to be some smoother solution for this or am I doing this completly wrong? When I look at the WASM Samples, they pick up the AppRoles with their token and the Controller simply can use the [Authorize(Roles = "xyz")] Attribute. What am I missing here? :/
Btw, this is how my Program.cs looks right now:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(options =>
{
builder.Configuration.Bind("AzureAd", options);
options.TokenValidationParameters.RoleClaimType =
"admin";
options.TokenValidationParameters.RoleClaimType = "doku";
},
options => { builder.Configuration.Bind("AzureAd", options); });
Thank you guys/gals <3
Please check if the given references are of use in your case.
A SERVER API app can authorize users to access secure API endpoints with authorization policies for security groups, AAD Administrator Roles, and App Roles
In Program.cs of a SERVER app, specify the claim as roleclaim
example:
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(options =>
{
Configuration.Bind("AzureAd", options);
options.TokenValidationParameters.RoleClaimType =
"http://schemas.microsoft.com/ws/2008/06/identity/claims/role";
},
options => { Configuration.Bind("AzureAd", options); });
Then you can use admin role on authorization controller to access
[Authorize(Roles = "admin")]
Here in App roles section you can see the configuration for both
server and client.
Edit the app role in the manifest editor in portal and then give
proper api permissions , expose scopes and grant permission for admin
consent >see Add app roles and get them from a token .And the
procedural logic must contain those scopes required by api.
Note : The appRoles manifest property of both the client and the
server Azure portal app registrations must include the same configured
roles.
Please check this for more detailed information which guides for both server and client apps.
Other references:
using-app-roles-with-AAD-blazor-server-client scenario | codemaze.com
quickstart-configure-app-expose-web-apis
quickstart-configure-app-access-web-apis
In scope of a compliance monitoring app for our powerapps usage, we created a C# console app which crawls powerapps.
environments
applications
permissions
(similar REST call than powershell commands Get-AdminPowerAppEnvironment Get-AdminPowerApp provided by Microsoft.PowerApps.Administration cmdlets)
proof of concept was done by stealing the Bearer header from fiddler when connected with my admin AAD account. POC is now validated, time to make it clean. And as often with AAD auth flow (for me), it's more complex than expected (sum up of hours of try & fails).
I find really little internet reference on how to authenticated & crawl (this part is ok) this API.
I tried different auth workflow and lib
MSAL
ADAL
fiddler on top of powershell command (but in powershell I'm not using a service principal)
and either I can't spot the correct scope or my service principal has no permission on the resource.
I have an App registration called AAA powerapps with ... quite a lot of permission (try & fails)
Created a client secret
just in case, put into Power Apps administrator
string authority = $"https://login.microsoftonline.com/[tenant-guid]/";
var app = ConfidentialClientApplicationBuilder
.CreateWithApplicationOptions(new ConfidentialClientApplicationOptions { ClientId = "[client-id]", ClientSecret = "[shhuuuu]" })
.WithAuthority(authority).Build();
// tried with https://management.azure.com/.default / https://api.bap.microsoft.com/.default / https://service.powerapps.com./default
var token = app.AcquireTokenForClient(new[] { "https://management.azure.com/.default" }).ExecuteAsync().Result;
//var client = new RestClient("https://api.bap.microsoft.com/providers/Microsoft.BusinessAppPlatform/scopes/admin/environments?api-version=2016-11-01");
var client = new RestClient("https://management.azure.com/providers/Microsoft.BusinessAppPlatform/scopes/admin/environments?api-version=2016-11-01");
var request = new RestRequest(Method.GET);
request.AddHeader("Authorization", "Bearer " + token.AccessToken);
IRestResponse response = client2.Execute(request);
I get a token, but I don't think it's on the correct scope/resource unfortunately.
Depending on the scope, I either get
Forbidden
{"error":
{"code":"Forbidden","message":"The service principal with id '[service principal guid (not client id)'
for application <null> does not have permission to access the path 'https://api.bap.microsoft.com:11779/providers/Microsoft.BusinessAppPlatform/scopes/admin/environments?api-version=2016-11-01' in tenant [tenant-guid]."}}
or
Unauthorized
{"error":{"code":"AuthenticationFailed","message":"Authentication failed."}}
Didn't succeed with client id & client secret but managed to call api.bap.microsoft.com/../Microsoft.BusinessAppPlatform with AAD user.
eg https://api.bap.microsoft.com/providers/Microsoft.BusinessAppPlatform/scopes/admin/environments?api-version=2016-11-01
re-used same method as Microsoft.PowerApps.Administration cmdlets
AAD account with AAD Power platform administrator role
If Multi Factor Access enabled for admin, create exception rule
use ADAL nuget Microsoft.IdentityModel.Clients.ActiveDirectory
dotnet
AuthenticationContext authContext = new AuthenticationContext("https://login.windows.net/common");
var credentials = new UserPasswordCredential("admin_powerapps#domain.net", "password");
// "1950a258-227b-4e31-a9cf-717495945fc2" = client ID for Azure PowerShell.
// available for any online version
var token = authContext.AcquireTokenAsync("https://management.azure.com/", "1950a258-227b-4e31-a9cf-717495945fc2", credentials).Result;
// any REST call
Header "Authorization" : "Bearer " + token.AccessToken
Endpoint : https://api.bap.microsoft.com/providers/Microsoft.BusinessAppPlatform/scopes/admin/environments?api-version=2016-11-01
results
The benefit from this method is that it can crawl "all" environments seamlessly (not sure the approach with creating a user on each was working).
Another approach I spotted was using Powerapps connector for admin but it involved extra configuration on each environments and required a license.
Not fully sure this method would be supported long term (eg xx.windows.net). Open minded for any other suggestion.
I was facing the same issue. What solved it with me is to register the app with tenant admin rights on the power platform admin using this command New-PowerAppManagementApp. Please, find MSFT article here.
After your client application is registered in Azure AD, it also needs to be registered with Microsoft Power Platform. Today, there's no way to do this via the Power Platform admin center; it must be done programmatically via Power Platform API or PowerShell for Power Platform administrators. A service principal cannot register itself—by design, the application must be registered by an administrator username and password context. This ensures that the application is created knowingly by someone who is an administrator for the tenant.
$appId = "CLIENT_ID_FROM_AZURE_APP"
# Login interactively with a tenant administrator for Power Platform
Add-PowerAppsAccount -Endpoint prod -TenantID $tenantId
# Register a new application, this gives the SPN / client application same permissions as a tenant admin
New-PowerAppManagementApp -ApplicationId $appId
I am following an older tutorial (https://code.msdn.microsoft.com/Write-Sample-App-for-79e55502) that shows how to create a web application that connects to an Azure Active Directory tenant using ADAL. There is a class library that contains DirectoryService classes that I believe does the work in retrieving AD user properties. I am wanting to create a login method for this project for security purposes, and to be able to identify what user is logged in to the application. Currently there is not a signin method that authenticates against AD by entering a username/password, so I am a little puzzled at how the app can retrieve user properties with just the AppId,Domain,and AppSecret in the Web.config without actually having someone login with either their AD creds or redirecting to login.microsoftonline/{tenantId}.....I do not know if I am making sense, but I want to be able to add a login method so a user is forced to login so it gets the claims for that specific user but if I am already using ADAL, can I also incorporate Owin?
There are two parts to your question -
1. How is this app working today, without asking end users to explicitly sign in
This sample is using Client Credential Grant, in which you don't need end users to sign in, but use the identity of an application itself to get the auth token and use it for further operations. As you mention yourself, it just needs AppId, Domain and App Secret from web.config. You can read all about it here - Client Credentials Grant
Related code to acquire token is available in MVCDirectoryGraphSample\Helpers\MVCGraphServiceHelper.cs file
AuthenticationContext authenticationContext = new AuthenticationContext(authString);
ClientCredential clientCred = new ClientCredential(ConfigurationManager.AppSettings["AppPrincipalId"],
2. How to add a login method to force users to sign in to your web application
You can start using something like Authorization Code Grant flow, instead of client credentials. Look here for documentation on different scenarios that Azure AD supports. Your case looks like a web application calling Graph API, described here
Exact code sample to do this is available here - Code Samples
I am writing a C# .NET app. It is connected to our service on Azure which is configured for using AAD. In turn, our service tries to make calls to Exchange via EWS.
This all worked fine for me until we recently deployed our service bits to a new Azure web app with new app registrations. They are all configured correctly and other developers on our team can authenticate with the service and use it as expected.
When I try to connect to the service, I get the following error:
AADSTS65001: The user or administrator has not consented to use the application with ID '61a8b794-7f67-4a01-9094-fcdd45693eaa'. Send an interactive authorization request for this user and resource.
Trace ID: ece7c5d0-2ecb-4096-a87a-2cd33271d65d
Correlation ID: 093b5935-3b06-4d76-91a9-6619bc179544
Timestamp: 2017-02-09 23:19:28Z
The consent prompt never appeared for me when trying to connect after deploying the new service.
I'm not sure what it is about my user account that causes this error to occur (it happens on multiple machines with my account) while others can connect successfully.
Here’s some of the code used to acquire the token in the service:
var bootstrapContext = ClaimsPrincipal.Current.Identities.First().BootstrapContext as System.IdentityModel.Tokens.BootstrapContext;
var upn = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Upn);
var email = ClaimsPrincipal.Current.FindFirst(ClaimTypes.Email);
var userName = upn != null ? upn.Value : email?.Value;
accessToken = bootstrapContext.Token;
ClientCredential clientCred = new ClientCredential("61a8b794-7f67-4a01-9094-fcdd45693eaa", appKey);
UserAssertion assertion = new UserAssertion(accessToken, "urn:ietf:params:oauth:grant-type:jwt-bearer", userName);
AuthenticationContext authContext = new AuthenticationContext("https://login.microsoftonline.com/microsoft.onmicrosoft.com");
AuthResult = authContext.AcquireToken("https://outlook.office365.com", clientCred, assertion);
Any ideas why I wouldn't get the consent prompt, but other users on my team have?
Based on the description, you are developing multi-tier application using Azure AD.
Since you mentioned this issue was occurred after using the new app, did you config your new app as the knownClientApplications of your service app(61a8b794-7f67-4a01-9094-fcdd45693eaa)?
If yes, you should can give the consent for the service app when you sign-in your web app( refer here about multi-tier applications).
The problem why only you get this issue may others have given the consent to this app before.
Please let me know if it helps.
I am working on a Messaging Application built using WPF and WCF-RESTful site.
This application is used inside intranet as well as internet. The application prompts for authentication (custom login screen in the messaging application) when it accessed through internet (outside the domain).
We have written authentication logic in the WCF service like below:
using (PrincipalContext pc = new PrincipalContext(ContextType.Domain, domain))
{
if (!pc.ValidateCredentials(userName, password, ContextOptions.Negotiate))
{
return string.Empty;
}
}
The Website's application pool is set to use NetworkService. The website's authentication is "Anonymous" as the Intranet User's do not require to authenticate.
I do not get any error or exception. Instead, it always returns "false" for any username even though the credential are correct.
Can you please tell me what I am missing here?
Take a look here http://travisspencer.com/blog/2009/07/creating-users-that-work-with.html plus if userName is in format domain\userName try to parse it from the domain name and send only the user part as argument to ValidateCredentials