Microsoft Identity Platform - User Token Cache args.Account is always null - c#

I have an MVC web application wanting to send emails from one email address using Office365. I am calling the API so that it shows up the microsoftonline login page for signing in. On successful sign in I am receiving the code back from API and generating Microsoft.Identity.Client.AuthenticationResult with the help of code and saving tokenresponse.UniqueId and tokenresponse.Account.HomeAccountId.Identifier in database.
I got to following page and signed in successfully and my database has the response saved.
After this I am trying to send emails using following code:
IConfidentialClientApplication mailer;
var mailerbuilder = ConfidentialClientApplicationBuilder
.Create(o365setpQry.ClientId))
.WithAuthority(AzureCloudInstance.AzurePublic, o365setpQry.Tenant)
.WithClientSecret(o365setpQry.ClientSecret);
mailerbuilder.WithRedirectUri(O365OAuthRedirectURL);
mailer = mailerbuilder.Build();
//user token cache.
mailer.UserTokenCache.SetAfterAccess((args) => {
Users user;
if **(args.Account == null)** user = null;
else user = _users.Table.Where(x => x.email_address == args.Account.Username).FirstOrDefault();
if (user == null)
{
var emsetp = _emsetp.Table.FirstOrDefault();
if (args.HasStateChanged || (emsetp.o365_GlobalTokenInfo == null))
{
emsetp.o365_GlobalTokenInfo = args.TokenCache.SerializeMsalV3();
}
}
else if (args.HasStateChanged || (user.o365_TokenInfo == null))
{
user.o365_TokenInfo = args.TokenCache.SerializeMsalV3();
_users.Update(user);
}
});
webEmailer.UserTokenCache.SetBeforeAccess((args) => {
Users user;
**if (args.Account == null)** user = null;
else user = _users.Table.Where(x => x.email_address == args.Account.Username).FirstOrDefault();
if (user == null)
{
args.TokenCache.DeserializeMsalV3(_emsetp.Table.FirstOrDefault().o365_GlobalTokenInfo);
}
else if (user.o365_TokenInfo != null)
{
args.TokenCache.DeserializeMsalV3(user.o365_TokenInfo);
}
});
var t = mailer.GetAccountAsync(emsetp.FirstOrDefault().o365_GlobalToken);
t.Wait();
Microsoft.Identity.Client.IAccount acct = t.Result;
The args.Account is returning null always.
var RequestClient = GraphClientFactory.Create(new DelegateAuthenticationProvider(new AuthenticateRequestAsyncDelegate((args) => {
var tokenRequest = mailer.AcquireTokenSilent(scopes, acct).ExecuteAsync();
tokenRequest.Wait();
args.Headers.Authorization = new AuthenticationHeaderValue("Bearer", tokenRequest.Result.AccessToken);
return System.Threading.Tasks.Task.FromResult(0);
})));
var graphClient = new GraphServiceClient(RequestClient);
var t = graphClient.Me.SendMail(message, true).Request();
var u = t.PostAsync();
I made sure my redirect urls are matching and I am not getting any errors from the API calls to see what is wrong and what makes args.Account value null and thus am not able to send emails. If I request the sign in page again it still shows the account I am signed in with.

Related

Creating a unique user session ID in ASP.NET C#

I'm not very experienced when it comes to development and I'm trying to secure an application so please bear with me. At the moment, the user is being authenticated and a new session is created using the following code:
public static void NewSession(Account account)
{
var redirectUrl = "Login.aspx";
if (account == null)
{
var sessionCookie = HttpContext.Current.Request.Cookies["test-app-session"];
if (sessionCookie != null)
ExpireCookie(sessionCookie);
}
else
{
var sessionCookie = new HttpCookie("test-app-session");
sessionCookie.Values["account-id"] = account.Id.ToString();
sessionCookie.Expires = DateTime.Now.AddHours(12);
HttpContext.Current.Response.Cookies.Add(sessionCookie);
var redirectCookie = HttpContext.Current.Request.Cookies["test-app-redirect"];
if (redirectCookie != null)
{
redirectUrl = redirectCookie.Values["url"];
ExpireCookie(redirectCookie);
}
if (string.IsNullOrWhiteSpace(redirectUrl))
redirectUrl = "Default.aspx";
}
HttpContext.Current.Response.Redirect(redirectUrl);
}
When the App validates the session, it then uses the below code:
public static Account FromSession()
{
var sessionCookie = HttpContext.Current.Request.Cookies["test-app-session"];
if (sessionCookie != null && long.TryParse(sessionCookie.Values["account-id"], out long accountId))
{
using (var db = Database.Connect())
{
using (var cmd = db.Command("SELECT * FROM Account WHERE id=#id").Parameter("#id", accountId, DbType.Int64))
using (var reader = cmd.ExecuteReader())
if (reader.Read())
return new Account(reader);
}
}
if (!Path.GetFileName(HttpContext.Current.Request.Path).Equals("Login.aspx", StringComparison.OrdinalIgnoreCase))
{
var redirectCookie = new HttpCookie("test-app-redirect");
redirectCookie.Values["url"] = HttpContext.Current.Request.Url.ToString();
redirectCookie.Expires = DateTime.Now.AddHours(1);
HttpContext.Current.Response.Cookies.Add(redirectCookie);
HttpContext.Current.Response.Redirect("Login.aspx");
}
return null;
}
The problem is that the account-id value can be easily guessed, so I want to use a unique value for this. I don't really know how I'd implement this, as I'm not sure how the value would then be tied to the users session if there isn't an identifier I can check against. Obviously I'm missing something fundamental in how session management is supposed to work, but I can't figure out what it is. If I create a GUID to store in the cookie, the browser saves it and knows what it is, but how does the server know what this ID is and link it to the user?

Sign in with Apple in .Net MAUI

I am currently working on an dotnet maui app and I need to integrate Sign in With Apple. But when I click the sign in button, It shows "invalid_request invalid web redirect url"
Tried solutions
I tried the solutions available here, but it is not working.
Other than that I have also read the documentation, also got help from tutorials such as this, this and this
Code
Initializing request:
//Initiating apple sign in request
WebAuthenticatorResult result = null;
if (scheme.Equals(Constants.apple, StringComparison.Ordinal)
&& DeviceInfo.Platform == DevicePlatform.iOS
&& DeviceInfo.Version.Major >= 13)
{
// Make sure to enable Apple Sign In in both the
// entitlements and the provisioning profile.
var options = new AppleSignInAuthenticator.Options
{
IncludeEmailScope = true,
IncludeFullNameScope = true,
};
result = await AppleSignInAuthenticator.AuthenticateAsync(options);
}
else
{
var authUrl = new Uri(Constants.authenticationUrl + scheme);
var callbackUrl = new Uri(Constants.callbackUrl);
result = await WebAuthenticator.AuthenticateAsync(authUrl, callbackUrl);
}
AuthToken = string.Empty;
// Get Name and Email from callback url
//if (result.Properties.TryGetValue("name", out var name) && !string.IsNullOrEmpty(name))
// AuthToken += $"Name: {name}{Environment.NewLine}";
//if (result.Properties.TryGetValue("email", out var email) && !string.IsNullOrEmpty(email))
// AuthToken += $"Email: {email}{Environment.NewLine}";
AuthToken += result?.AccessToken ?? result?.IdToken;
AuthCredential credential = null;
Handling results:
// WebAuthenticator Endpoint - use for social login e.g. Google, Facebook, Apple etc.
const string callbackScheme = "socialloginauthenticator";
[HttpGet("{scheme}")]
public async Task Get([FromRoute] string scheme)
{
var auth = await Request.HttpContext.AuthenticateAsync(scheme);
if (!auth.Succeeded
|| auth?.Principal == null
|| !auth.Principal.Identities.Any(id => id.IsAuthenticated)
|| string.IsNullOrEmpty(auth.Properties.GetTokenValue("access_token")))
{
// Not authenticated, challenge
await Request.HttpContext.ChallengeAsync(scheme);
}
else
{
var claims = auth.Principal.Identities.FirstOrDefault()?.Claims;
var email = string.Empty;
email = claims?.FirstOrDefault(c => c.Type == System.Security.Claims.ClaimTypes.Email)?.Value;
// Get parameters to send back to the callback
var qs = new Dictionary<string, string>
{
{ "access_token", auth.Properties.GetTokenValue("access_token") },
{ "refresh_token", auth.Properties.GetTokenValue("refresh_token") ?? string.Empty },
{ "expires_in", (auth.Properties.ExpiresUtc?.ToUnixTimeSeconds() ?? -1).ToString() },
{ "email", email }
};
// Build the result url
var url = callbackScheme + "://#" + string.Join(
"&",
qs.Where(kvp => !string.IsNullOrEmpty(kvp.Value) && kvp.Value != "-1")
.Select(kvp => $"{WebUtility.UrlEncode(kvp.Key)}={WebUtility.UrlEncode(kvp.Value)}"));
// Redirect to final url
Request.HttpContext.Response.Redirect(url);
}
}
I have resolved the issue. The issue was with redirect uri in apple service I made.
The required uri was of format "www.example.com/signin-apple" while I was following "www.example.com/path/to/endpoints"

Get Azure AD User Group details for particular User

We are working to integrate ASP.NET MVC web application with Azure PaaS. We are trying to get the User AD group from Azure Active directory but we have received the "Authorization Required" error.
DLL used: Microsoft.Azure.ActiveDirectory.GraphClient
Code used:
public async Task GetGroups(string objectId) {
IList groupMembership = new List();
try
{
if (objectId != null)
{
ActiveDirectoryClient client = AuthenticationHelper.GetActiveDirectoryClient();
IUser user = await client.Users.GetByObjectId(objectId).ExecuteAsync();
var userFetcher = (IUserFetcher)user;
IPagedCollection<IDirectoryObject> pagedCollection = await userFetcher.MemberOf.ExecuteAsync();
List<string> groupsname = new List<string>();
do
{
List<IDirectoryObject> directoryObjects = pagedCollection.CurrentPage.ToList();
foreach (IDirectoryObject directoryObject in directoryObjects)
{
if (directoryObject is Group)
{
var group = directoryObject as Group;
groupMembership.Add(group);
groupsname.Add(group.DisplayName);
}
}
pagedCollection = await pagedCollection.GetNextPageAsync();
} while (pagedCollection != null);
string groupscsv = string.Join(",", groupsname.ToArray());
System.Web.HttpContext.Current.Session["Groups"] = groupscsv;
Response.Redirect("~/Index.aspx");
}
}
catch (Exception e)
{
if (Request.QueryString["reauth"] == "True")
{
//
// Send an OpenID Connect sign-in request to get a new set of tokens.
// If the user still has a valid session with Azure AD, they will not be prompted for their credentials.
// The OpenID Connect middleware will return to this controller after the sign-in response has been handled.
//
HttpContext.GetOwinContext()
.Authentication.Challenge(OpenIdConnectAuthenticationDefaults.AuthenticationType);
}
//
// The user needs to re-authorize. Show them a message to that effect.
//
ViewBag.ErrorMessage = "AuthorizationRequired";
return View();
}
Kindly help us to fix this issue or provide any other sample source to get the user AD groups from Azure Active Directory.

Get Tweets by LinqToTwitter

I'm trying to get tweets from Twitter but it's not working with me, here is the code:
var auth = new SingleUserAuthorizer
{
CredentialStore = new SingleUserInMemoryCredentialStore()
{
ConsumerKey = ConfigurationManager.AppSettings["***"],
ConsumerSecret = ConfigurationManager.AppSettings["***"],
AccessToken = ConfigurationManager.AppSettings["***"],
AccessTokenSecret = ConfigurationManager.AppSettings["***"]
}
};
var context = new TwitterContext(auth);
var tweets =
from tw in context.Status
where
tw.Type == StatusType.User &&
tw.ScreenName == "***"
select tw;
// handle exceptions, twitter service might be down
try
{
// map to list
tweets
.Take(3)
.Select(t =>
new Tweets
{
//Username = t.ScreenName,
//FullName = t.User.Name,
TweetText = t.Text,
//FormattedText = ParseTweet(t.Text)
})
.ToList();
}
catch (Exception) { }
every time it fail when I'm trying to read the tweets, the exception is
LinqToTwitter.TwitterQueryException: Bad Authentication data
But I'm sure that the credentials are correct.
and also is it possible to read the posts of another twitter account? like a company account or a celebrate account?
LINQ to Twitter is async, so you should change your query like this:
var tweets =
await
(from tw in context.Status
where
tw.Type == StatusType.User &&
tw.ScreenName == "***"
select tw)
.ToListAsync();
Also, hit a breakpoint after instantiating auth and inspect Credentials to make sure you've populated them correctly.

Get The Username/User Id Of Currently Logged In User In A UWP App

I want to get the username or user id of the currently logged in user in a UWP app. Below is the code that I am using but it returns null.
var current = users.Where(p => p.AuthenticationStatus == UserAuthenticationStatus.LocallyAuthenticated && p.Type == UserType.LocalUser).FirstOrDefault();
var data = await current.GetPropertyAsync(KnownUserProperties.AccountName);
Username = (string)data;
var users = await User.FindAllAsync(UserType.LocalUser);
var user = (string) await users.FirstOrDefault().GetPropertyAsync(KnownUserProperties.AccountName);
var domain = "";
var host = "";
if (string.IsNullOrEmpty(user))
{
var domainWithUser = (string) await users.FirstOrDefault().GetPropertyAsync(KnownUserProperties.DomainName);
domain = domainWithUser.Split('\\')[0];
user = domainWithUser.Split('\\')[1];
}
This helped me. reference http://codegur.com/33736983/get-environment-variables-in-net-core-uwp

Categories