WCF Service with Domain Validation - wpf

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

Related

Create GraphClient with UsernamePasswordProvider with client secret

I created a desktop application that talks to Graph API (Beta).
In the development version, I deployed it on the application I created myself on Azure AD. As one of the requirements is not to show login dialog when using the application, I decided to go with UsernamePasswordProvider, which I provide the user name and password of my account and everything works fine (I didn't put client secret in my application).
When I'm about to deploy it on customer's network, I asked the admin and he provides me the service user name, password, tenant ID, client ID, and a client secret.
I tried using Postman to check if I can get an access token from those info and I can only if I provide the client secret along with user name and password.
When I'm back to the code, UsernamePasswordProvider's constructor accepts IPublicClientApplication which has no option to create the application with client secret.
I understand that there is a reason behind as the secret can be easily stolen if the application got decompiled but, if I'm (in fact, my client) not serious about this, is there any way to initialize the GraphClient by putting user name, password, and client secret together for authentication?
Important, the Username / Password flow is not recommended because your application asking a user for their password is not secure. For more information about this problem, see this article.
If you still would like to use it, you could put username and password of that user in Key Vault and fetch those in your code.
string keyVaultName = Environment.GetEnvironmentVariable("KEY_VAULT_NAME");
var kvUri = "https://" + keyVaultName + ".vault.azure.net";
var client = new SecretClient(new Uri(kvUri), new DefaultAzureCredential());
var secret = client.GetSecret(secretName); // get username or password here
I recommend you to use ClientCredentialsProvider, it enables service applications to run without user interaction.

Azure AD Enterprise Application - Identify Caller Application

I have a REST API which uses Azure ADD App registration to allow other apps to call it.
In the Azure Portal, I have registered it as an Enterprise Application and also registered the consumer applications and assigned them Roles appropriately.
The authentication and RBAC works fine.
But the use case that I am working on requires me to identify and log the incoming request calling application's name (The one seen in the portal as 'Display Name', when we view the list of users and groups for an enterprise Application).
As advised in the internet, I am using some Identity related API to read the claims from the request header.
var provider = claimsUser.FindFirst("http://schemas.microsoft.com/identity/claims/identityprovider").Value;
var sid = claimsUser.FindFirst(ClaimTypes.NameIdentifier).Value;
OR
var sid = claimsUser.FindFirst("stable_sid").Value;
But this gives me a GUID value which I couldn't map to any of the consumers of the Enterprise Application.
The clients are all registered in the Azure portal.
In the Portal, I can see the apps in the "Users and Groups" section for the Enterprise application, with their appropriate roles.
In terms of usage, before making the call, the clients generate a bearer token based on the certificate that they get from Azure. The make the call with the bearer token attached to the request header. This bearer token is validated against the Azure AD, in the filters set before every controller..
What I want is to get are the details about this client who has made the call.. As per some repliers, and, to which I agree, the Guid that I get as part of the previous call mentioned above is for the actual user and not the app itself which is making the call.
Can anyone throw some light into it.. some code snippet will be of real help..
I'm not sure what authentication flow you are using, but SID is generally for a user that's logged in, not an application. if your client applications are using client id and secret, the token it returns that you send to the api should include the app registration guid. https://learn.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-client-creds-grant-flow#access-control-lists . So the appid and iss should give you the guid of the app registration. using this, you can make a call to graph api, to identify the display name of the app registration. https://learn.microsoft.com/en-us/graph/api/application-get?view=graph-rest-1.0&tabs=http
If your app is a user login app, and you don't want to make a call to graph, the other option you could do as a workaround would be to create app roles and assign users to them but name the app roles with some convention that includes the app's display name. then the name could come through under roles claim.. https://learn.microsoft.com/en-us/azure/active-directory/develop/howto-add-app-roles-in-azure-ad-apps
those are some options.. but other than calling graph or kinda working around to inject the name into a different claim of the token I'm not sure of any other method to get the "app registration's display name"

Azure Active Directory Web Application without login current user

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

Error AADSTS65001 but no consent prompt for just one user

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.

Can I use ASPNetIdentity and ActiveDirectory?

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!

Resources