ADAL V3, Azure Data Lake, Certificates and ServiceClientCredentials - c#

I am in a bit of a jam, I need to access Azure Event Hub and Azure Data Lake from the same service principal in the same piece of code (C#). The service principal is an Azure AD application and I am authenticating with a certificate.
If I use ADAL 2.x and authenticate I can connect to Azure Data Lake fine, but Event Hubs (WindowsAzure.ServiceBus) is not able to authenticate (see further down).
The ADAL 2.x code I use for creating the credential for Azure Data Lake is as below, this works 100% fine:
public static ServiceClientCredentials GetCreds_SPI_Cert(string tenant, Uri tokenAudience, string clientId, string certificateThumbprint)
{
var certificate = FindCertificateByThumbprint(certificateThumbprint);
SynchronizationContext.SetSynchronizationContext(new SynchronizationContext());
var clientAssertionCertificate = new ClientAssertionCertificate(clientId, certificate);
var serviceSettings = ActiveDirectoryServiceSettings.Azure;
serviceSettings.TokenAudience = tokenAudience;
var creds = ApplicationTokenProvider.LoginSilentWithCertificateAsync(tenant, clientAssertionCertificate, serviceSettings).GetAwaiter().GetResult();
return creds;
}
If I upgrade to ADAL v3 in order to gain access the Event Hub (WindowsAzure.ServiceBus requires it), then the following code works fine (for event hub):
public static TokenProvider GetTokenProviderViaCetificate(string tenant, Uri tokenAudience, string clientId, string certificateThumbprint)
{
var certificate = FindCertificateByThumbprint(certificateThumbprint);
return TokenProvider.CreateAadTokenProvider(
new AuthenticationContext($"https://login.windows.net/{tenant}"),
new ClientAssertionCertificate(clientId, certificate),
ServiceAudience.EventHubsAudience);
}
Note that the token provider in the Event Hub authentication CreateAadTokenProvider is only available in ADALv3. The Service Bus and Data Lake clients also both require different types of credential.
If I use ADAL V3 and go back to the Data Lake code, the GetCreds_SPI_Cert fails with the following error:
Method not found:
'System.Threading.Tasks.Task`1
Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext.AcquireTokenAsync(System.String,
Microsoft.IdentityModel.Clients.ActiveDirectory.ClientAssertionCertificate)'.
In short, how do I use ADAL v3 to authenticate an Azure AD App service principal against Azure Data Lake (using a certificate)? I can't downgrade to ADAL 2.x due to the Event Hub dependency.

Something that could aid devise a solution, albeit perhaps not the solution directly, is an authentication adapter documented deep in the github repo:
https://github.com/Azure/azure-sdk-for-net/blob/3f736b5af3851ab99bbaa98483ae537de0d48cfb/Documentation/AuthConflictsBetweenSDKs.md
Authentication conflicts can happen due to mixing old SDKs* and new
SDKs*. SDKs that depend on The credential types created by the new
authentication library
(Microsoft.Rest.ClientRuntime.Azure.Authentication, type =
ServiceClientCredentials) are incompatible with the credential types
used in older SDKs (Microsoft.Azure.Common, type =
SubscriptionCloudCredentials). The problem is that using two different
authentication libraries will require you to authenticate twice, which
is a painful experience.
public class SubscriptionCredentialsAdapter : SubscriptionCloudCredentials
{
ServiceClientCredentials _credentials;
string _subscriptionId;
public SubscriptionCredentialsAdapter(ServiceClientCredentials wrapped, string subscriptionId)
{
_credentials = wrapped;
_subscriptionId = subscriptionId;
}
public override string SubscriptionId
{
get { return _subscriptionId; }
}
public override Task ProcessHttpRequestAsync(HttpRequestMessage request, CancellationToken cancellationToken)
{
return _credentials.ProcessHttpRequestAsync(request, cancellationToken);
}
}

Related

Authenticate Azure AD using Provided Access Token

I tried to find an Azure authentication mechanism that uses an access token as a parameter. but no luck. I just found ClientSecretCredential class that use tenant id, client id, and client secret as a parameter like below :
var clientSecretCredential = new ClientSecretCredential(tenantId, clientId, clientSecret);
the reason I need the that is the access token will be generated by another service and my service will only accept access token to be used to authenticate Azure AD.
Actually, I can utilize Azure Management RestAPI to do that. However to improve developer experience I'd like to utilize .NET client library if possible.
I have tried to find documentation in Azure Identity client library in https://learn.microsoft.com/en-us/dotnet/api/overview/azure/identity-readme?view=azure-dotnet, but I couldn't find any class or method that I need.
If you want tokens from azure ad you can use using Microsoft.IdentityModel.Clients.ActiveDirectory; library to get the tokens.
I am assuming that you have already created an azure ad app registration and already possess the client_id , client_secret and tenant_id. Just save this as strings in code.
Now we can use the clientcredential along with authenticationContext we can acquire tokens.
Complete program :
string client_id = "";
string client_secret = "";
string tenant_id = "";
string endpoint = "https://login.microsoftonline.com/"+tenant_id;
ClientCredential credent = new ClientCredential(client_id , client_secret);
var context = new AuthenticationContext(endpoint);
var result = context.AcquireTokenAsync("https://management.azure.com/",credent);
var result = context.AcquireTokenAsync("https://management.azure.com/",credent);
Console.WriteLine(result.Result.AccessToken);
Here result.Result.AccessToken will give you a access token in form of a token.

Access to Azure KeyVault with Azure.Identity in Xamarin.Forms application

I have a Xamarin.Forms application. I need an Azure Storage to store some data. I don't want to store the Shared Access Signature (SAS) in my application, obviously.
In my application, I've develop a KeyVaultService:
private readonly Azure.Security.KeyVault.Secrets.SecretClient _keyVaultSecretClient;
public KeyVaultService()
=> _keyVaultSecretClient = new(
new Uri("https://foo.vault.azure.net/"),
new DefaultCredential());
// ...
public async Task<string> GetSecretAsync(string secretName)
{
// ...
var response = await _keyVaultSecretClient.GetSecretAsync(secretName);
// ...
return response.Value.Value;
}
A AzureStorageService:
private readonly IKeyVaultService _keyVaultService;
public AzureStorageService() => _keyVaultService = DependencyService.Get<IKeyVaultService>();
public async Task<byte[]> GetFooAsync()
{
var connectionString = await _keyVaultService.GetSecretAsync(STORAGE_CONNECTIONSTRING);
_blobContainerClient = new BlobContainerClient(connectionString, CONTAINER_NAME);
}
And it's called like that:
byte[]? fooBytes = await _azureStorageService.GetFooAsync();
await DoSomething(fooBytes);
Tests
The second parameter of SecretClient is a Azure.Identity.TokenCredential derived class. With my _keyVaultSecretClient instance, in my KeyVaultService, I have tried to use some classes (DefaultAzureCredential, ClientSecretCredential, ...):
DefaultAzureCredential and ClientSecretCredential
public KeyVaultService() => new(new Uri("foo...."), new DefaultAzureCredential())
and
public KeyVaultService() => new(new Uri("foo...."), new ClientSecretCredential(TENANT_ID, CLIENT_ID, CLIENT_SECRET))
An exception throws:
Azure.Identity.AuthenticationFailedException:
'ClientSecretCredential authentication failed: Confidential Client flows are not available on mobile platforms or on Mac.See https://aka.ms/msal-net-confidential-availability for details.'
Inner Exception:
PlatformNotSupportedException: Confidential Client flows are not available on mobile platforms or on Mac.See https://aka.ms/msal-net-confidential-availability for details.
And I don't want to keep Tenant ID, Client ID or Secret ID in my code
EnvironmentCredential
public KeyVaultService() => new(new Uri("foo...."), new EnvironmentCredential())
I have add 3 environment variables on my Windows: AZURE_CLIENT_ID, AZURE_CLIENT_SECRET and AZURE_TENANT_ID.
AuthenticationFailedException is thrown, again.
ManagedIdentityCredentials
public KeyVaultService() => new(new Uri("foo...."), new ManagedIdentityCredential(CLIENT_ID))
Another exception throws:
Azure.Identity.CredentialUnavailableException:
'ManagedIdentityCredential authentication unavailable. No Managed Identity endpoint found.'
Where and how can I add an Identity endpoint?
The client ID is in the code!! Nooo :(
Information
Mobile Apps + Key Vault Don't do it
I have read this blog post: https://codemilltech.com/mobile-apps-azure-keyvault-dont-do-it/, But... If an anonymous user found the url of my Azure Function... He can read my Key Vault address... And my application throws the same exceptions... I think is my approach.
Develop an Azure Function which access to Key Vault and his secrets, then sends them back to me through an API? Ooh: All of my secrets can be leaked. No thanks.
I have read the link provided by the exception (https://aka.ms/msal-net-confidential-availability). MSAL? Why for Azure? From what I understood, MSAL allows to connect to Microsoft Graph and Office 365 APIs...
In resume
I understand that my approach is not available on mobile platforms (The exception is self-explanatory enough to guess, I promise) - because a phone is not entirely secure device?
So,
what is the implementation to use an Azure Key Vault or another solution to securely access to my Azure Storage?
In fact,
I want to have not the secrets in my code;
I want access to an Azure Storage with a SAS, to a SAP server with username/password and another external services (stored in the Key Vault - or another securely way).
Someone has an idea?
Thanks in advance :-)

Why doesn’t the "https://login.microsoftonline.com/common" AAD endpoint work, while the "https://login.microsoftonline.com/[tenant ID]" does?

I’m developing a UWP application that calls an API. The API is made of an Azure Function triggered by HTTP requests. I want the Azure Function to be secured through Azure Active Directory. To do so, I created two app registrations in AAD, one for the UWP and one for the API. Both support accounts in any organizational directory (Any Azure AD directory - Multitenant) and personal Microsoft accounts (e.g., Skype, Xbox). The API app registration provides scope, and the UWP app registration uses that scope. The code I use on my UWP is:
var HttpClient _httpClient = new HttpClient();
const string clientId = "[UWP app registration’s client ID]";
const string authority = "https://login.microsoftonline.com/[Tenant ID of the UWP app registration]";
string[] scopes = { "api://[API app registration’s client ID]/[scope]" };
var app = PublicClientApplicationBuilder
.Create(clientId)
.WithAuthority(authority)
.WithRedirectUri("https://login.microsoftonline.com/common/oauth2/nativeclient")
.Build();
AuthenticationResult result;
var accounts = await app.GetAccountsAsync();
try {
result = await app.AcquireTokenSilent(scopes, accounts.FirstOrDefault()).ExecuteAsync();
}
catch (MsalUiRequiredException) {
try {
result = await app.AcquireTokenInteractive(scopes).ExecuteAsync();
}
catch (Exception exception) {
Console.WriteLine(exception);
throw;
}
}
if (result == null) return;
_httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
var response = _httpClient.GetAsync("[API URL]").Result;
This code works, but if I replace the authority with https://login.microsoftonline.com/common (as specified here), being my app registrations multi-tenant, I get a 401 response when calling the API _httpClient.GetAsync("[API URL]").Result. The docs say the code must be updated somehow when using the /common endpoint, but I don’t understand how I should edit it. I also tried to follow these tips, but without success, while these seem not to be related to my case since I’m not building an IWA. If I run the working version of the code, result is populated with an object whose TenantId property gets the right value of the tenant that owns the app registrations while using the not-working version of the code, result is populated with an object whose TenantId property gets a value I don’t know where it’s coming from.
Can anyone help me, please?
Here's my understanding of AAD multitenancy flow :
The common authority can't be used to get a token. It's used as a common endpoint to get the templated server metadata :
v1 : https://login.microsoftonline.com/common/.well-known/openid-configuration
v2 : https://login.microsoftonline.com/common/v2.0/.well-known/openid-configuration
A token should be requested from the issuer where the client is defined.
But the common authority can be used in a multitenant API (eg your Azure Functions API) to verify that a client has a valid AAD token. From the documentation :
Because the /common endpoint doesn’t correspond to a tenant and isn’t an issuer, when you examine the issuer value in the metadata for /common it has a templated URL instead of an actual value : https://sts.windows.net/{tenantid}/
Therefore, a multi-tenant application can’t validate tokens just by matching the issuer value in the metadata with the issuer value in the token. A multi-tenant application needs logic to decide which issuer values are valid and which are not based on the tenant ID portion of the issuer value.

Application is not supported over the /common or /consumers endpoints. Please use the /organizations or tenant-specific endpoint

I know there are several other posts listed about this topic but I cannot seem to find any useful info in them to apply to my own application. I am building a .Net MVC Web App that uses the Microsoft Graph API. I followed another project (https://github.com/microsoftgraph/aspnet-snippets-sample) but when I launch the application, it redirects to https://login.microsoftonline.com where it attempts to log in using a Microsoft work account, and redirects back to the homepage. However, after entering Microsoft account credentials and before being redirected back, I am shown an error:
.
Below is a section from my Startup.Auth.cs that I believe is causing the problems. If anyone can see anything that seems off or has any insight on this topic, I would greatly appreciate it. I have been spinning my wheels just trying to sign-in to this application using Open Id Connect to be able to use the Microsoft Graph API. Thanks!
app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions {
// The `Authority` represents the v2.0 endpoint - https://login.microsoftonline.com/common/v2.0
// The `Scope` describes the permissions that your app will need. See https://azure.microsoft.com/documentation/articles/active-directory-v2-scopes/
ClientId = appId,
* * Authority = String.Format(CultureInfo.InvariantCulture, aadInstance, "common", "/v2.0"), * *
RedirectUri = redirectUri,
Scope = scopes,
PostLogoutRedirectUri = redirectUri,
TokenValidationParameters = new TokenValidationParameters {
ValidateIssuer = false,
},
Notifications = new OpenIdConnectAuthenticationNotifications {
AuthorizationCodeReceived = async(context) => {
var code = context.Code;
string signedInUserID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
string graphScopes = nonAdminScopes;
string[] scopes = graphScopes.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries);
ConfidentialClientApplication cca = new ConfidentialClientApplication(appId, redirectUri,
new ClientCredential(appSecret),
new SessionTokenCache(signedInUserID, context.OwinContext.Environment["System.Web.HttpContextBase"] as HttpContextBase).GetMsalCacheInstance(), null);
AuthenticationResult result = await cca.AcquireTokenByAuthorizationCodeAsync(code, scopes);
// Check whether the login is from the MSA tenant.
// The sample uses this attribute to disable UI buttons for unsupported operations when the user is logged in with an MSA account.
var currentTenantId = context.AuthenticationTicket.Identity.FindFirst("http://schemas.microsoft.com/identity/claims/tenantid").Value;
if (currentTenantId == "xxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx") {
HttpContext.Current.Session.Add("AccountType", "msa");
}
// Set IsAdmin session variable to false, since the user hasn't consented to admin scopes yet.
HttpContext.Current.Session.Add("IsAdmin", false);
},
AuthenticationFailed = (context) => {
context.HandleResponse();
context.Response.Redirect("/Error?message=" + context.Exception.Message);
return Task.FromResult(0);
}
}
});
This error is usually caused by an incompatibility between your app registration and the authentication library you are using.
The code in that sample is using the Microsoft Authentication Library (MSAL), which uses the Azure V2 OAuth endpoints, which supports converged auth (both Azure AD accounts and Microsoft accounts). In order for the v2 auth endpoints to work, your app registration MUST come from https://apps.dev.microsoft.com.
If you register your app on the Azure portal (https://portal.azure.com), you'll see this error. That's because the Azure portal registers the app using the Azure v1 OAuth schema.
There is also a case where the https://apps.dev.microsoft.com portal can create a v1 registration. If you login to that portal and you see more than one grouping of apps, with multiple "Add an app" buttons, you need to choose the "Add an app" button for Converged Apps.
If you are using microsoftgraph/msgraph-sdk-dotnet-auth for getting access token, then /common endpoint is valid.
If you are using AzureAD/microsoft-authentication-library-for-java for getting access token, then use /organizations endpoint instead of /common.
Unfortunatelly adding Converged Apps from https://apps.dev.microsoft.com/ is no longer supported by MS. They redirect to Azure portal from there.

Token based implementation in webapi to secure endpoints

I am having a web application with web service and client will register their application using my web application.
Now client will have application of type SPA or mobile apps and they will consume my webservices from their apps.
So I would be implementing token based mechanism for securing access to my endpoints.
1) But here I am confused that shall I use any framework to generate access token or I can use any library which will generate any random string which i will send in response.for instance something like this :
TokenId = Convert.ToBase64String(Guid.NewGuid().ToByteArray()).Replace("+", "_")
So while registering application if client have enabled authentication for their application then user will be validated and then I will return access token and also save accesstoken in my database with that user id.
So my database table would be like below for storing validated accesstoken :
Id(autogenerated) accesstoken userid clientid createdat expiresat
So after user is authenticated and now if user want to access any protected resources then user need to pass this access token in subsequent call in header.
So what I will do I will get access token from header and then validate that accesstoken against that database and then allow access to my protected resource other wise user would get authorized.
I have seen lots of things related to this so basically this is oauth2 and I want to implement this.
I have seen Openid connect(this project doesnt even compile) which is on top of oauth2 and which is used for authentication and oauth2 will be used for authorization.
But here as I am storing access token in my database so here is my doubt related to that :
2) Now do I need openconnectid (but this project doesn't even compile) for validating access token or as I am having storing access token in my database I don't need openconnectid?
3) I want to implement asp.net identity but then I will receive dynamic database connection string and as i have seen asp.net identity mostly works with entity framework I couldn't find any source where I could use ado.net to validate username and password using SQL query. I know I can do something like this :
Make a custom user class which implements IUser as described here
Define a custom user store which implements
public class UserStoreService
: IUserStore<CustomUser>, IUserPasswordStore<CustomUser>
But I won't be having this information as I don't have fixed connection string.connection string again is stored in database with client registration.
4) We have given user a fixed endpoint through which client can create an admin so for that I will use my RSA algorithm for password hashing and then store it in database. So with this now do i need to use asp.net identity?
5) I have seen lots of following link with token based implementation but I am not getting where they are validating accesstoken in which part but now as I am having accesstoken stored in my database do I need to use any of the following implementation?
http://bitoftech.net/2014/10/27/json-web-token-asp-net-web-api-2-jwt-owin-authorization-server/
http://bitoftech.net/2014/06/01/token-based-authentication-asp-net-web-api-2-owin-asp-net-identity/
6) Moreover if for any client if client don't want authentication for its respective application then what I will do is I will don't have that username password validation but I will simply generate accesstoken and then send in response so then in every subsequent request that access token will be pass to access protected resources.Do you think this make sense?
I have never seen any example where access token is store in database and problem with storing access token in database would be I have to make a call to database every time to validate access token for each endpoint.
Update :
Use case of my webservice engine would be:
1) Support multiple client application.
2) Manage user session in the form of token management for each client application. So here as most of the article is storing accesstoken in identity and that identity is validated inside [Authorize] attribute in which accesstoken is also validated and based on that user is allowed to access protected resources.This is what my understanding is up until now.
So if I also user identity and store user context inside identity supporting multiple client application is a good idea?
From “7.1. Access Token Representation” in “Full-Scratch Implementor of OAuth and OpenID Connect Talks About Findings” :
How should an access token be represented? There are two major ways.
As a meaningless random string. Information associated with an access
token is stored in a database table behind an authorization server.
As a self-contained string which is a result of encoding access token
information by base64url or something similar.
Pros and cons of these two ways are described in the blog.
If access tokens are random strings, pieces of information associated with the access tokens (user ID, client ID, scopes, lifetime, etc.) are stored in a database which is managed by the authorization server which have issued the access tokens.
Whenever a resource server which exposes APIs accepts an API call from a client application, the resource server has to get the information about the access token in some way or other.
If the resource server can access the database managed by the authorization server (in other words, if the resource server and the authorization server shares the database), the resource server can get the information about the access token from the database directly.
Otherwise, the resource server has to make an API call to the authorization server to get the information. In this case, it can be expected that the authorization server exposes an API which complies with RFC 7662 (OAuth 2.0 Token Introspection). Note that some implementations may provide a more developer-friendly API than RFC 7662 (e.g. “4. Introspection Access Token”).
Anyway, your resource server doesn't necessarily have to make a DB call (or an introspection API call to the authorization server) every time if the server caches information about access tokens in a memory cache or somewhere else appropriate.
BTW, what you need when you want to protect APIs is access tokens. Therefore, your system doesn't have to support OpenID Connect which is a specification as to how to request and issue ID tokens. You may be confused because a server which supports OpenID Connect can issue access tokens, too, in addition to ID tokens. See “Diagrams of All The OpenID Connect Flows” to understand what a server which supports OpenID Connect issues.
Finally, identity management, user authentication, and OAuth 2.0 & OpenID Connect don't necessarily have to be implemented in a monolithic way. See “New Architecture of OAuth 2.0 and OpenID Connect Implementation” for details.
No, you don't need to store the access_token on the database. You can decrypt the JWT and read the information as you are the one who encrypts it with a secret key. (By default it's the machine key.)
Identity has a off the self support for Oauth. You have to just configure it properly. You can set-up the configuration for OAuthAuthorizationServerOptions in the Startup.Auth.cs. Sample code as follows. I have tried to answer most of your question in comments in the code.
public static OAuthAuthorizationServerOptions OAuthOptions { get; private set; }
public static string PublicClientId { get; private set; }
public void ConfigureOAuth(IAppBuilder app)
{
// Configure the application for OAuth based flow
PublicClientId = "theDragonIsAlive";
OAuthOptions = new OAuthAuthorizationServerOptions
{
TokenEndpointPath = new PathString("/Token"),
Provider = new YourOwnApplicationOAuthProvider(PublicClientId),
//AuthorizeEndpointPath = new PathString("/Access/Account"),
AccessTokenExpireTimeSpan = TimeSpan.FromDays(7)
//AllowInsecureHttp = true
};
// Enable the application to use bearer tokens to authenticate users
app.UseOAuthBearerTokens(OAuthOptions);
}
public class ApplicationOAuthProvider : OAuthAuthorizationServerProvider
{
private readonly string _publicClientId;
public ApplicationOAuthProvider(string publicClientId)
{
if (publicClientId == null)
{
throw new ArgumentNullException("publicClientId");
}
_publicClientId = publicClientId;
}
public override async Task GrantResourceOwnerCredentials(OAuthGrantResourceOwnerCredentialsContext context)
{
var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
// This where you are validating the username and password credentials.
ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
if (user == null)
{
context.SetError("Dragon Fire:", "The user name or password is incorrect. You shall be burnt.");
return;
}
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
OAuthDefaults.AuthenticationType);
AuthenticationProperties properties = CreateProperties(user.UserName);
AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
context.Validated(ticket);
context.Request.Context.Authentication.SignIn(oAuthIdentity);
}
public override Task TokenEndpoint(OAuthTokenEndpointContext context)
{
foreach (KeyValuePair<string, string> property in context.Properties.Dictionary)
{
context.AdditionalResponseParameters.Add(property.Key, property.Value);
}
return Task.FromResult<object>(null);
}
// This method is where you will create the client access token.
// First you get the client, you can place values from the client record into the tokens claim collection.
// You then create a new ClaimsIdentity.
// You add some claims, in the example client name is added.
// Create an AuthenticationTicket using your claims identity.
// Validate the ticket (you do need to do this or the client will be considered unauthenticated)
//public override Task GrantClientCredentials(OAuthGrantClientCredentialsContext context)
//{
// var client = clientService.GetClient(context.ClientId);
// var oAuthIdentity = new ClaimsIdentity(context.Options.AuthenticationType);
// oAuthIdentity.AddClaim(new Claim(ClaimTypes.Name, client.ClientName));
// var ticket = new AuthenticationTicket(oAuthIdentity, new AuthenticationProperties());
// context.Validated(ticket);
// return base.GrantClientCredentials(context);
//}
// This method has to be implmented when you are maintaining a list of clients which you will allow.
// This method is for validating the input, you can used this method to verify the client id and secret are valid.
public override Task ValidateClientAuthentication(OAuthValidateClientAuthenticationContext context)
{
//string clientId;
//string clientSecret;
//context.TryGetFormCredentials(out clientId, out clientSecret);
//if (clientId == "1234" && clientSecret == "12345")
//{
// context.Validated(clientId);
//}
//return base.ValidateClientAuthentication(context);
// Resource owner password credentials does not provide a client ID.
if (context.ClientId == null)
{
context.Validated();
}
return Task.FromResult<object>(null);
}
public override Task ValidateClientRedirectUri(OAuthValidateClientRedirectUriContext context)
{
if (context.ClientId == _publicClientId)
{
Uri expectedRootUri = new Uri(context.Request.Uri, "/");
if (expectedRootUri.AbsoluteUri == context.RedirectUri)
{
context.Validated();
}
}
return Task.FromResult<object>(null);
}
public static AuthenticationProperties CreateProperties(string userName)
{
IDictionary<string, string> data = new Dictionary<string, string>
{
{ "userName", userName }
};
return new AuthenticationProperties(data);
}
}
The sample code above does not have separate client classifications. It will treat all users as a single type of client. But I have given some example code in the comments which will guide you to get started in the right direction.
Disclaimer: I am not an expert on this(yet) and my setup is different. I had an existing MVC application with Owin and I had to build a webapi on top of it. This was my prototype code and it did the job. You will have to improve in it for your production code. Have fun and good luck.

Categories

Resources