ADFS vNext Client Authentication (WPF) (Windows Server 2016 Preview 3) - wpf

I have a Windows Server 2016 TechnicalPreview 3 with a configured ADFS vNext, as first client I have created an MVC Application as a ReplingPartyTrust.
The authentication with the ADFS work really well with the MVC Application.
Now to the problem: I have written a Native Application (WPF) which i want to authenticate against the ADFS.
The Steps i did are:
To inform the ADFS of my new WPF Client i ran the the following PowerShell Script:
Add-ADFSClient -ClientType Public -Name “MyClient” -ClientId “E1CF1107-FF90-4228-93BF-26052DD2C714” -RedirectUri “https://E1CF1107-FF90-4228-93BF-26052DD2C714/redir´”
To authenticate the client (Code-Wise) i used the following NuGet-Package:
Microsoft.IdentityModel.Clients.ActiveDirectory (3.5 (Alpha))
Then I wrote the following code:
string authority = "https://win2016preview.server.local/adfs/ls";
string resourceURI = "https://adfs.server.local/MyMVCApp";
string clientReturnURI = "https://e1cf1107-ff90-4228-93bf-26052dd2c714/redir";
string clientID = "E1CF1107-FF90-4228-93BF-26052DD2C714";
var ac = new AuthenticationContext(authority, false);
var ar = await ac.AcquireTokenAsync(resourceURI, clientID, new
Uri(clientReturnURI),
new PlatformParameters(PromptBehavior.Auto, new
WindowInteropHelper(this).Handle));
With this code, the client should authenticate at the ADFS (over OAuth i think) and prompt the user to enter his organisation credentials.
If i run the application this window appears:
I choose Yes (Ja) and the credential prompt opens. In the same time the following exception occures
In the event log if the server ADFS the following error message appears:
Microsoft.IdentityServer.Web.Protocols.OAuth.Exceptions.OAuthAuthorizationUnauthorizedClientException: MSIS9321: Received invalid OAuth request. The client 'E1CF1107-FF90-4228-93BF-26052DD2C714' is forbidden to access the resource 'https://adfs.server.local/MyMVCApp.
at Microsoft.IdentityServer.Web.Protocols.OAuth.OAuthAuthorization.OAuthAuthorizationRequestContext.ValidateCore()
at Microsoft.IdentityServer.Web.Protocols.ProtocolContext.Validate()
at Microsoft.IdentityServer.Web.Protocols.OAuth.OAuthAuthorization.OAuthAuthorizationProtocolHandler.GetRequiredPipelineBehaviors(ProtocolContext pContext)
at Microsoft.IdentityServer.Web.PassiveProtocolListener.GatherDeviceSecurityToken(ProtocolContext protocolContext, PassiveProtocolHandler protocolHandler)
at Microsoft.IdentityServer.Web.PassiveProtocolListener.OnGetContext(WrappedHttpListenerContext context)
As far as i can tell, the ADFS recognizes the Client Id and tries to authenticate it. But the ADFS rejects the Client.
Did i forget to configure something? The client should just prompt the user, which authenticates against the ADFS, so the client can habe the AuthenticationToken.
I hope you can follow me. Thank you in advance!

The solution is very simple :)
Add the property IssuanceAuthorizationRules (Add-ADFSRelyingPartyTrust )
-IssuanceAuthorizationRules '=> issue (Type = "http://schemas.microsoft.com/authorization/claims/permit" value = "true");'

Related

Error "invalid_client" when trying to get a token from Microsoft API

I'm trying to develop a drive solution (Onedrive) in a windev program.
I created an application in Microsoft Azure and created a secret key.
When doing the first request https://login.live.com/oauth20_authorize.srf?client_id={client_id}&scope={scope} &response_type=code&redirect_uri={redirect_uri} I'm redirected on the connection page.
Once I'm connected I get a code back as https://login.live.com/oauth20_authorize.srf?code={code}.
But when I ask for a token posting this request : POST https://login.live.com/oauth20_token.srf Content-Type: application/x-www-form-urlencoded client_id={client_id}&redirect_uri={redirect_uri}&client_secret={client_secret} &code={code}&grant_type=authorization_code
I get this back
{ "error":"invalid_client", "error_description":"The client does not exist or is not enabled for consumers. If you are the application developer, configure a new application through the App Registrations in the Azure Portal at https:\/\/go.microsoft.com\/fwlink\/?linkid=2083908.", "correlation_id":"471e800c-69b4-43c6-a03f-a1f7e9512e6b" }
Thank you for your help.
This error means you are using a Microsoft Account to login your client app, but it is not enabled for that.
To change the setting for an existing AD App, navigate to the Manifest blade of it in the portal, find the signInAudience attribute, set it with AzureADandPersonalMicrosoftAccount or PersonalMicrosoftAccount.

deamon authentication on powerapps admin REST API

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

Get SharePoint Office 365 data using Client Id

I am accessing SharePoint online list data using the following code but i get the following error.
The remote server returned an error: (403) Forbidden.
The web forms application is running in Azure and uses Azure authentication. I would like to use the same credentials for authentication
string siteUrl = "[url]";
string aadAppId = "[appid]";
string clientSecret = "[redacted]";
OfficeDevPnP.Core.AuthenticationManager authManager = new OfficeDevPnP.Core.AuthenticationManager();
ClientContext context = authManager.GetAzureADNativeApplicationAuthenticatedContext(siteUrl, aadAppId, appurl, null, AzureEnvironment.Production);
if (context != null)
{
Web web = context.Web;
context.Load(web);
context.ExecuteQuery();
}
I do not want to access the SharePoint using the user credentials.
I have enabled AAD Azure authentication on the web app. The web app authenticates with Azure credentials.
On the CORS setting i have also set the Domain Url to "https://domainname.sharepoint.com";
In the manage permissions section of AAD app I have given the app Permission to read and write sharepoint list and web data.
You example is attempting to retrieve a token as a native client application, which is an app that cannot keep a secret and cannot authenticate by itself. (That's why you'll notice you never use clientSecret.)
If you want to use OfficePnP, you can try one of the AuthenticationManager.GetAzureADAppOnlyAuthenticatedContext methods to authenticate in the app-only context. Note that they all require a certificate for authentication, rather than a secret.

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.

WCF Service with Domain Validation

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

Resources