Hi I have Local Db and Azure Ad Connect with OpenId connect login.
when user login by using Azure Ad we got claims and object id in claims.
What is happening after that claims are overridden by identity because that
user has entry in AspNetUser too.
I have to keep both local db login and azure ad login but need to check if user is from azure ad
login then the object should be in local db which will be seeded later in local db or we can say that it is in local db, how to create a way where our both user can use the app.
this code is where I am using the OpenId connect and then then checking the claims
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, "Login To Azure Ad", options =>
{
options.Authority = string.Format(configuration["AzureAd:Instance"], configuration["AzureAd:TenantId"]);
options.ClientId = configuration["AzureAd:ClientId"];
options.ResponseType = OpenIdConnectResponseType.CodeIdToken;
options.CallbackPath = configuration["AzureAd:CallbackPath"];
options.RequireHttpsMetadata = false;
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.ClientSecret = "abX8Q~OQpPs04CW6hEWWr7tQfQRLXc47htf5Xasn";
options.Scope.Add("email");
options.SignInScheme = IdentityConstants.ExternalScheme;
options.Events = new OpenIdConnectEvents
{
OnAuthorizationCodeReceived = async ctx =>
{
var request = ctx.HttpContext.Request;
var currentUri = UriHelper.BuildAbsolute(request.Scheme, request.Host, request.PathBase, request.Path);
var credential = new ClientCredential(ctx.Options.ClientId, ctx.Options.ClientSecret);
var distributedCache = ctx.HttpContext.RequestServices.GetRequiredService<IDistributedCache>();
string userId = ctx.Principal?.Claims?.Where(m => m.Type == "oid")?.FirstOrDefault()?.Value ?? string.Empty;
foreach (var item in ctx.Principal?.Claims)
{
ctx.HttpContext.User.Claims.Append(item);// binding it claims
}
}
};
});
Image 1 : here in HomeController I used custom Authorize(CustomerAuthorize) to check the upcoming claims.
Image 2 : like this in after login from azure ad I am getting the required data
now here after my custom authorize the claims are over ridden by identity.
Image 3 : I just want to authenticate azure ad user by it's claims values
Help me to find any solution.
Related
Am developing a full stack web application where in client part of the app am using angular and .net core web api as the backend part of the application, am stack on how i can get the user roles from the backend into the client app when user login successfully into the system since am using jwt authentication, am able to get the email address which i added it in claims identity if user exists in the database as below
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.Email, obj.Email)
})
and from client application am getting this user email by decoding the token sent from backend after successfully login as
In Typescript File
var tokenData = jwtHelper.decodeToken(token);
In HTML form
{{ tokenData.email }}
Therefore, i don't know how i can add roles in claims identity together with email added and obtain them from token in angular app where i can use them as user permissions to access components in client application, thank you in advance.
The easiest way is to add roles to your claims with a loop. This is a complete method for creating jwt tokens.
public string GenarateToken(User user)
{
var claims =new List<Claim>()
{
new Claim(ClaimTypes.NameIdentifier, user.Id.ToString()),
new Claim(ClaimTypes.Name, user.UserName),
};
foreach (var role in user.Roles)
{
claims.Add(new Claim(ClaimTypes.Role, role.Name));
}
var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_conf.GetSection("AppSettings:secret").Value));
var cred = new SigningCredentials(key, SecurityAlgorithms.HmacSha512Signature);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(claims),
Expires = DateTime.Now.AddDays(1),
SigningCredentials = cred
};
var tokenHandler = new JwtSecurityTokenHandler();
var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
I have gmail API service account details = client id and service account. How can I just send an email from one id to other without OAuth?
I want to authorize this email sending process with the service account credentials only.
Is there a nuget package that can help fulfill this requirement?
How can I just send an email from one id to other without OAuth?
I assume what you mean is how to send an email with out poping up the Oauth2 consent screen.
Using a service account will allow you to do that, once you have configured the permissions properly in your google workspace account. You grant the service account to preform actions on behalf of one of your domain users. This way the service account can send emails as that user without the user having to consent to that access because you have pre authorized it via google workspace.
The following code will show you how to authorize your application to use a service account.
class Program
{
public static string Base64Encode(string plainText)
{
var plainTextBytes = System.Text.Encoding.UTF8.GetBytes(plainText);
return System.Convert.ToBase64String(plainTextBytes);
}
public static void SendMail()
{
try
{
string ApplicationName = "Gmail API .NET Quickstart";
const string serviceAccount = "xxxx#xxxx-api.iam.gserviceaccount.com";
var certificate = new X509Certificate2(#"c:\XXXX.p12", "notasecret", X509KeyStorageFlags.Exportable);
var gsuiteUser = "YourDomain#YourDomain.com";
var serviceAccountCredentialInitializer = new ServiceAccountCredential.Initializer(serviceAccount)
{
User = gsuiteUser,
Scopes = new[] { GmailService.Scope.GmailSend, GmailService.Scope.GmailLabels }
}.FromCertificate(certificate);
var credential = new ServiceAccountCredential(serviceAccountCredentialInitializer);
if (!credential.RequestAccessTokenAsync(CancellationToken.None).Result)
throw new InvalidOperationException("Access token failed.");
var service = new GmailService(new BaseClientService.Initializer()
{
HttpClientInitializer = credential,
ApplicationName = ApplicationName,
});
var mailMessage = new MailMessage();
mailMessage.From = new MailAddress("se#Yourdomain.com");
mailMessage.To.Add("ddddd#hotmail.com");
mailMessage.ReplyToList.Add("se#Yourdomain.com");
mailMessage.Subject = "test";
mailMessage.Body = "<h1>sdf</h1>";
mailMessage.IsBodyHtml = true;
//foreach (System.Net.Mail.Attachment attachment in email.Attachments)
//{
// mailMessage.Attachments.Add(attachment);
//}
var mimeMessage = MimeKit.MimeMessage.CreateFromMailMessage(mailMessage);
var gmailMessage = new Message
{
Raw = Base64Encode(mimeMessage.ToString())
};
Message message1 = new Message();
UsersResource.MessagesResource.SendRequest sendRequest = service.Users.Messages.Send(gmailMessage, "me");
var s = sendRequest.Execute();
Console.WriteLine("Message delivered!");
}
catch (Exception ep)
{
Console.WriteLine(ep.ToString());
}
}
The trick is to remember to set up the domain wide delegation properly and to decide which user the service account is going to be impersonating and to remember to add that email
without google workspace
If you do not have a google workspace account then you can not use service accounts. You may want to consider going though the smtp server instead.
I wrote an application which should read the groups of a user. I am using Asp.net core. I created an application inside the azure portal and granted all application permissions for GraphAPI and clicked on the Grant permission button. Then I used some code similar to WebApp-GroupClaims-DotNet to retrieve the users groups:
public async Task<IEnumerable<string>> GetGroupIdsFromGraphApiAsync(string userId)
{
var groupObjectIds = new List<string>();
// Acquire the Access Token
var credential = new ClientCredential(_configHelper.ClientId, _configHelper.AppKey);
var authContext = new AuthenticationContext(_configHelper.Authority);
var result = await authContext.AcquireTokenAsync(_configHelper.GraphResourceId, credential);
var accessToken = result.AccessToken;
var requestUrl =
$"{_configHelper.GraphResourceId}/{_configHelper.Domain}/users/{userId}/getMemberGroups?api-version=1.6";
// Prepare and Make the POST request
var client = new HttpClient();
var request = new HttpRequestMessage(HttpMethod.Post, requestUrl);
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
var content = new StringContent("{\"securityEnabledOnly\":false}");
content.Headers.ContentType = new MediaTypeHeaderValue("application/json");
request.Content = content;
var response = await client.SendAsync(request);
// Endpoint returns JSON with an array of Group ObjectIDs
if (response.IsSuccessStatusCode)
{
var responseContent = await response.Content.ReadAsStringAsync();
var groupsResult = (Json.Decode(responseContent)).value;
foreach (string groupObjectId in groupsResult)
groupObjectIds.Add(groupObjectId);
}
else
{
var responseContent = await response.Content.ReadAsStringAsync();
throw new WebException(responseContent);
}
return groupObjectIds;
}
Unfortunately I do always get the following response:
{"odata.error":{"code":"Authorization_RequestDenied","message":{"lang":"en","value":"Insufficient privileges to complete the operation."}}}
Is there no way for an application to query the AD for this information?
According to your code , you are making Azure ad graph api calls , Then you need to grant permission for Windows Azure Active Directory(azure ad graph api ) .
https://graph.windows.net is the endpoint for Azure AD Graph APi , in azure portal the name is Windows Azure Active Directory . https://graph.microsoft.com is the the endpoint for Microsoft Graph api , in azure portal the name is Microsoft Graph
I've created an application with asp.net mvc api with users, following this tutorial. And everything works great like that. local users and facebook login works fine.
But now I'm trying to use the FacebookClient and get the user info and friends.
But it asks me for the token, but is not the same token that is stored on my session or cookie.
In api controller Account, in GetExternalLogin action I have this code:
if (hasRegistered)
{
Authentication.SignOut(DefaultAuthenticationTypes.ExternalCookie);
ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(UserManager,
OAuthDefaults.AuthenticationType);
ClaimsIdentity cookieIdentity = await user.GenerateUserIdentityAsync(UserManager,
CookieAuthenticationDefaults.AuthenticationType);
AuthenticationProperties properties = ApplicationOAuthProvider.CreateProperties(user.UserName);
Authentication.SignIn(properties, oAuthIdentity, cookieIdentity);
}
else
{
IEnumerable<Claim> claims = externalLogin.GetClaims();
ClaimsIdentity identity = new ClaimsIdentity(claims, OAuthDefaults.AuthenticationType);
Authentication.SignIn(identity);
}
Here I can find the claims. But not how to use this
My question is how can I store the facebook token on my api after the login?
var options = new FacebookAuthenticationOptions
{
AppId = "Your App ID",
AppSecret = "Your App Secret",
Provider = new FacebookAuthenticationProvider
{
OnAuthenticated = async context =>
{
// Retrieve the OAuth access token to store for subsequent API calls
string accessToken = context.AccessToken;
// Retrieve the username
string facebookUserName = context.UserName;
// You can even retrieve the full JSON-serialized user
var serializedUser = context.User;
}
}
};
app.UseFacebookAuthentication(options);
For more info on how to do this stuff see here: http://www.oauthforaspnet.com/providers/facebook/
f the OnAuthenticated you could also add:
context.Identity.AddClaim(new Claim("FacebookToken", accessToken));
As I am pretty sure that at this point we have created the user and created their claims so you
I'm having troubles with OAuth .NET backend authentication for Azure mobile-services in ASP.NET 5.0. I'm trying to implement external login with Facebook,Twitter,Google and Microsoft.
I'm successfully getting access_token from all external sources and then trying to log in into MobileServiceClient.
here is my code
var app = System.Web.HttpContext.Current.Items["AzureClient"] as MobileServiceClient;
app.Logout();
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
var accesToken = loginInfo.ExternalIdentity.Claims.FirstOrDefault(c => c.Type == "access_token");
MobileServiceUser user = null;
if (providerName == "Microsoft")
{
user = await app.LoginWithMicrosoftAccountAsync(accessToken);
}
else
{
var token = new JObject();
token.Add("access_token", accessToken);
user = await app.LoginAsync(loginInfo.Login.LoginProvider, token);
}
And I'm getting authenticated but only with facebook token. Microsoft and Google throw 401 unauthorized exception. Twitter throws "Method not allowed". What am I dowing wrong?
I've double-checked that app secret and app keys are populated for all providers in azure management portal.
Please, help
I'm not sure if tokens from social network can be forwarded to MobileServiceClient or not but it works with facebook and doesn't work with all the others. I'm really puzzled about this behaviour;
I finally ended up with creating an ActiveDirectory application and using ADAL AcquireToken method to obtain AD token for my MobileServicesClient. As it is described here
Azure Website Single Sign On accessing Azure Mobile Service from Azure Active Directory as User
here is my Method obtaining token from AD
private string GetAdToken()
{
string clientID = "<clientId>";
string authority = "<AuthorityUrl>";
string resourceURI = "<WebApiUrl>";
var appKey = "<applicationKey>";
var ac = new Microsoft.IdentityModel.Clients.ActiveDirectory.AuthenticationContext(authority);
var clientCredential = new ClientCredential(clientID, appKey);
var ar = ac.AcquireToken(resourceURI, clientCredential);
Session["token"] = ar.AccessToken;
return ar.AccessToken;
}
and here is my method which is run before quering Azure datatables through MobileServiceClient.
private async Task<MobileServiceUser> EnsureLogin()
{
var app = System.Web.HttpContext.Current.Items["AzureClient"] as MobileServiceClient;
app.Logout();
JObject token = new JObject();
token["access_token"] = Session["token"].ToString();
return await app.LoginAsync(MobileServiceAuthenticationProvider.WindowsAzureActiveDirectory, token);
}
So now it doesn't metter what provider I use to log in to my web application. MobileServiceClient always works with ad token.
I'm not sure if it is an acceptable practice but it works and maybe this will help somebody like me struggling against azure authentication