Lost session data after MS AD Oauth2 redirect - azure

I am losing original session data after MS AD Oauth2 redirect back today. It is now a totally new session after redirect to and back from https://login.microsoftonline.com/**************/oauth2/v2.0/authorize". But, it worked a few days ago and failed now after some automatic windows10 updates (and rekeying some tfs password from credential manager.) However, If I use my GitHub authorization server, the same code works and keeps my session data: Session["state"]. What am I missing? Any help would be greatly appreciated! I am doing manual redirection using something like below:
private void SignUpOAuth()
{
var state = Guid.NewGuid().ToString();
var nonce = Guid.NewGuid().ToString();
var clientId = "*************";
var scope = "openid";
var serviceUrl = ConfigurationManager.AppSettings.Get("OAuthServiceUrl");
var redirectUrl = ConfigurationManager.AppSettings.Get("OAuthRedirectUrl");
var paramtersPart = string.Format("response_type={0}&client_id={1}&scope={2}&redirect_uri={3}&aud{4}&state={5}&nonce={6}&response_mode=form_post",
"id_token+code",
HttpUtility.UrlEncode(clientId),
HttpUtility.UrlEncode(scope),
HttpUtility.UrlEncode(redirectUrl),
HttpUtility.UrlEncode(serviceUrl),
state,
nonce);
_context.Session.Add("state", state);
_context.Session.Add("nonce", nonce);
_context.Response.Redirect($"{ serviceUrl}?{paramtersPart}", false);
}

Related

How to query MS Graph API in User Context?

I'm trying to change a user's password using MS Graph API. I was checking earlier questions like this and this where the answer were always similar: register an AAD application, because changing the password requires Delegated
UserAuthenticationMethod.ReadWrite.All permissions, and you cannot set that in a B2C application as a B2C app supports only offline_access and openid for Delegated.
So the answers were always suggesting creating an AAD app, and using this app I could query the Graph API on behalf of the user. The question is, how to achieve this? If I check the documentation from Microsoft: Get access on behalf of a user, it is saying that first you need to get authorization, only then you can proceed to get your access token.
But as part of the authorization process, there is a user consent screen. If I'm calling my ASP.NET Core Web API endpoint to change my password on behalf of my user, how will it work on the server? The client won't be able to consent, if I'm doing these calls on the server, right?
Also, I'm using Microsoft.Graph and Microsoft.Graph.Auth Nuget packages and it's not clear how to perform these calls on behalf of the user. I was trying to do this:
var client = new GraphServiceClient(new SimpleAuthProvider(authToken));
await client.Users[myUserId]
.ChangePassword(currentPassword, newPassword)
.Request()
.PostAsync();
Where SimpleAuthProvider is just a dummy IAuthProvider implementation.
Any ideas how to make this work?
OK, got it:
static void ChangePasswordOfAUser()
{
var myAzureId = "65e328e8-5017-4966-93f0-b651d5261e2c"; // id of B2C user
var currentPassword = "my_old_pwd";
var newPassword = "newPassword!";
using (var client = new HttpClient())
{
var passwordTokenRequest = new PasswordTokenRequest
{
Address = $"https://login.microsoftonline.com/{tenant}/oauth2/v2.0/token",
ClientId = clientId, // client ID of AAD app - not the B2C app!
ClientSecret = clientSecret,
UserName = $"{myAzureId}#contoso.onmicrosoft.com",
Password = currentPassword,
Scope = "https://graph.microsoft.com/.default" // you need to have delegate access
};
var response = client.RequestPasswordTokenAsync(passwordTokenRequest).Result;
var userAccessToken = response.AccessToken;
client.DefaultRequestHeaders.Add("Authorization", $"Bearer {userAccessToken}");
var json = System.Text.Json.JsonSerializer.Serialize(new
{
currentPassword = currentPassword,
newPassword = newPassword
});
var changePasswordResponse = client.PostAsync(
$"https://graph.microsoft.com/v1.0/users/{myAzureId}/changePassword",
new StringContent(json, Encoding.UTF8, "application/json"))
.Result;
changePasswordResponse.EnsureSuccessStatusCode();
}
}

dotnet Core - Using azure AD authentication to retrive data from sharepoint REST API

My project is set up to use azure ad as login(from the dotnet core template). I have successfully managed to log in.
However, i want to use the same logged in user to retrive data from sharepoint rest api.
I have the following method:
public async Task<FileResults> Test()
{
var siteUrl = "https://xxxxx.sharepoint.com";
var username = "xx#xx.no";
var password = "xxxxxx";
var securePassword = new SecureString();
password.ToCharArray().ToList().ForEach(c => securePassword.AppendChar(c));
var credentials = new SharePointOnlineCredentials(username, securePassword);
var handler = new HttpClientHandler();
handler.Credentials = credentials;
var uri = new Uri(siteUrl);
handler.CookieContainer.SetCookies(uri, credentials.GetAuthenticationCookie(uri));
var json = string.Empty;
using (var client = new HttpClient(handler))
{
client.DefaultRequestHeaders.Clear();
client.DefaultRequestHeaders.Add("Accept", "application/json;odata=verbose");
var response = await client.GetAsync(siteUrl + "/_api/Web/GetFolderByServerRelativeUrl('/Delte%20dokumenter/Test')/Files");
json = await response.Content.ReadAsStringAsync();
var result = Newtonsoft.Json.JsonConvert.DeserializeObject<Rootobject>(json);
var files = result.FileResults;
return files;
}
}
This is working fine and im getting documents from sharepoint.
But, this is when using hardcoded credentials. How do i use the credentials of the logged in user via azure AD? Do i retrive the accesstoken?
To use the Azure AD Authentication you need to have one of the Authentication flows.
Note: Username/Password flow is not recommended.
After that you will be getting the tokens according to the scopes that are specified and you need to hit the Microsoft Graph Api, internally you need to hit the SharePoint API endpoints according to your requirement.
You can start exploring with this sample

ADFS : Acquiring a Token programmatically

So we have built a set of Azure Functions that are secured by ADFS (MSAL)
We have configured an App in ADFS and got it all working well with our Android client.
We now want to do some API testing so we want to programmatically generate Auth tokens to test the API's
I can't get the following code to work at all, maybe I have the tenant ID wrong, in the App config, its a GUID (42b03d0b-d7f2-403e-b764-0dbdcf0505f6), but examples say it's our domain
string userName = "-";
string password = "-";
string clientId = "ee13c922-bf4b-4f0a-ba39-ea74e1203c6e";
var credentials = new UserPasswordCredential(userName, password);
var authenticationContext = new AuthenticationContext("https://login.microsoftonline.com/acostaonline.onmicrosoft.com");
var result = await authenticationContext.AcquireTokenAsync("https://graph.windows.net", clientId, credentials);
UPDATE
So changed the code to be MSAL and still trying to login via username and password. Now it just times out
string authority = "https://login.microsoftonline.com/42b03d0b-d7f2-403e-b764-0dbdcf0505f6/";
string[] scopes = new string[] { "user.read" };
PublicClientApplication app = new PublicClientApplication("ee13c922-bf4b-4f0a-ba39-ea74e1203c6e", authority);
var accounts = await app.GetAccountsAsync();
Microsoft.Identity.Client.AuthenticationResult result = null;
if (accounts.Any())
{
result = await app.AcquireTokenSilentAsync(scopes, accounts.FirstOrDefault());
}
else
{
try
{
var securePassword = new SecureString();
foreach (char c in "PASSWORD") // you should fetch the password keystroke
securePassword.AppendChar(c); // by keystroke
result = await app.AcquireTokenByUsernamePasswordAsync(scopes, "AUSER#acosta.com",
securePassword);
}
}
Error
SocketException: A connection attempt failed because the connected
party did not properly respond after a period of time, or established
connection failed because connected host has failed to respond
172.26.200.77:443
It seems that the code you provided is using ADAL instead of MSAL.
The main difference is that with ADAL you would use an AuthenticationContext to acquire tokens, whereas in MSAL you use ConfidentialClientApplication or PublicClientApplication, depending on if the application is running in a back-end or on the user's device.
Here is the article about Differences between ADAL.NET and MSAL.NET applications.
When you use MSAL.Net to get a token for the Microsoft Graph API, you could use the following code:
public static PublicClientApplication PublicClientApp = new
PublicClientApplication(ClientId);
var app = App.PublicClientApp;
ResultText.Text = string.Empty;
TokenInfoText.Text = string.Empty;
var accounts = await app.GetAccountsAsync();
authResult = await app.AcquireTokenSilentAsync(_scopes, accounts.FirstOrDefault());
For more details, you could refer to this article, in left menu also includes Android and iOS.

Sending IM with Skype for Business Online from Console App

I am trying to set up a C# console app that can send notifications/reminders to users via Skype for Business online from a generic AD account. I was excited to see the other day that according to this page, UCWA is now supported in Skype for Business online: https://msdn.microsoft.com/en-us/library/office/mt650889.aspx.
I've been trying to follow this tutorial to get this set up: https://msdn.microsoft.com/en-us/library/office/mt590891(v=office.16).aspx. So far I haven't really had much luck... I have my application set up in Azure AD but I get stuck at the "Requesting an access token using implicit grant flow" step of that article (not 100% certain I'm taking the correct actions before that either)... so far I have this:
string clientId = "xxxxxxxx"
string resourceUri = "https://webdir.online.lync.com";
string authorityUri = "https://login.windows.net/common/oauth2/authorize";
AuthenticationContext authContext = new AuthenticationContext(authorityUri);
UserCredential cred = new UserCredential("username", "password");
string token = authContext.AcquireToken(resourceUri, clientId, cred).AccessToken;
var poolReq = CreateRequest("https://webdir.online.lync.com/autodiscover/autodiscoverservice.svc/root", "GET",token);
var poolResp = GetResponse(poolReq);
dynamic tmp = JsonConvert.DeserializeObject(poolResp);
string resourcePool = tmp._links.user.href;
Console.WriteLine(resourcePool);
var accessTokenReq = CreateRequest("https://login.windows.net/common/oauth2/authorize"
+ "?response_type=id_token"
+ "&client_id=" + clientId
+ "&redirect_uri=https://login.live.com/oauth20_desktop.srf"
+ "&state=" + Guid.NewGuid().ToString()
+ "&resource=" + new Uri(resourcePool).Host.ToString()
, "GET",token);
var accessTokenResp = GetResponse(accessTokenReq);
my GetResponse and CreateRequest methods:
public static string GetResponse(HttpWebRequest request)
{
string response = string.Empty;
using (HttpWebResponse httpResponse = request.GetResponse() as System.Net.HttpWebResponse)
{
//Get StreamReader that holds the response stream
using (StreamReader reader = new System.IO.StreamReader(httpResponse.GetResponseStream()))
{
response = reader.ReadToEnd();
}
}
return response;
}
public static HttpWebRequest CreateRequest(string uri, string method, string accessToken)
{
HttpWebRequest request = System.Net.WebRequest.Create(uri) as System.Net.HttpWebRequest;
request.KeepAlive = true;
request.Method = method;
request.ContentLength = 0;
request.ContentType = "application/json";
request.Headers.Add("Authorization", String.Format("Bearer {0}", accessToken));
return request;
}
accessTokenResp is an office online logon page, not the access token I need to move forward... so I'm stuck. I've tried quite a few variations of the above code.
I've been scouring the net for more examples but can't really find any, especially since UCWA support for Office 365 is so new. Does anyone have an example of how to do what I am trying to do or can point me to one? Everything I've found so far hasn't really even been close to what I'm trying. I can't use the Skype for Business client SDK unfortunately either as it doesn't meet all of my requirements.
I came to a working solution using ADAL (v3), with the help of steps outlined at
Authentication using Azure AD
Here the steps, which involve requesting multiple authentication tokens to AAD using ADAL
Register your application, as Native Application, in Azure AD.
Perform autodiscovery to find user's UCWA root resource URI.
This can be done by performing a GET request on
GET https://webdir.online.lync.com/Autodiscover/AutodiscoverService.svc/root?originalDomain=yourdomain.onmicrosoft.com
Request an access token for the UCWA root resource returned in the autodiscovery response, using ADAL
For instance, your root resource will be at
https://webdir0e.online.lync.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=yourdomain.onmicrosoft.com
you'll have to obtain a token from AAD for resource https://webdir0e.online.lync.com/
Perform a GET on the root resource with the bearer token obtained from ADAL
GET https://webdir0e.online.lync.com/Autodiscover/AutodiscoverService.svc/root/oauth/user?originalDomain=yourdomain.onmicrosoft.com
This will return, within the user resource, the URI for applications resource, where to create your UCWA application. This in my case is:
https://webpoolam30e08.infra.lync.com/ucwa/oauth/v1/applications
Residing then in another domain, thus different audience / resource, not included in the auth token previously obatained
Acquire a new token from AAD for the host resource where the home pool and applications resource are (https://webpoolam30e08.infra.lync.com in my case)
Create a new UCWA application by doing a POST on the applications URI, using the token obtained from ADAL
Voilá, your UCWA application is created. What I notice at the moment, is that just few resources are available, excluding me / presence. So users' presence can be retrieved, but self presence status can't be changed.
I've been able however to retrieve my personal note, and the following resources are available to me:
people
communication
meetings
Show me some code:
Function to perform the flow obtaining and switching auth tokens
public static async Task<UcwaApp> Create365UcwaApp(UcwaAppSettings appSettings, Func<string, Task<OAuthToken>> acquireTokenFunc)
{
var result = new UcwaApp();
result.Settings = appSettings;
var rootResource = await result.Discover365RootResourceAsync(appSettings.DomainName);
var userUri = new Uri(rootResource.Resource.GetLinkUri("user"), UriKind.Absolute);
//Acquire a token for the domain where user resource is
var token = await acquireTokenFunc(userUri.GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped));
//Set Authorization Header with new token
result.AuthToken = token;
var usersResult = await result.GetUserResource(userUri.ToString());
//
result.ApplicationsUrl = usersResult.Resource.GetLinkUri("applications");
var appsHostUri = new Uri(result.ApplicationsUrl, UriKind.Absolute).GetComponents(UriComponents.SchemeAndServer, UriFormat.SafeUnescaped);
//Acquire a token for the domain where applications resource is
token = await acquireTokenFunc(appsHostUri);
//Set Authorization Header with new token
result.AuthToken = token;
//
var appResult = await result.CreateApplicationAsync(result.ApplicationsUrl, appSettings.ApplicationId, appSettings.UserAgent, appSettings.Culture);
return result;
}
Usage code ato retrieve OAuth tokens using ADAL
var ucSettings = new UcwaAppSettings
{
UserAgent = "Test Console",
Culture = "en-us",
DomainName = "yourdomain.onmicrosoft.com",
ApplicationId = "your app client id"
};
var acquireTokenFunc = new Func<string, Task<OAuthToken>>(async (resourceUri) =>
{
var authContext = new AuthenticationContext("https://login.windows.net/" + ucSettings.DomainName);
var ar = await authContext.AcquireTokenAsync(resourceUri,
ucSettings.ApplicationId,
new UserCredential("myusername", "mypassword"));
return new OAuthToken(ar.AccessTokenType, ar.AccessToken, ar.ExpiresOn.Ticks);
});
var app = await UcwaApp.Create365UcwaApp(ucSettings, acquireTokenFunc);
It should be of course possible to avoid hard-coding username and password using ADAL, but this was easier for PoC and especially in case of Console Application as you asked
I've just blogged about this using a start-to-finish example, hopefully it will help you. I only go as far as signing in, but you can use it with another post I've done on sending IMs using Skype Web SDK here (see day 13 and 14) and combine the two, it should work fine.
-tom
Similar to Massimo's solution, I've created a Skype for Business Online C# based console app that demonstrates how to sign and use UCWA to create/list/delete meetings and change user presence. I haven't gotten around to extending it to send IM's, but you're certainly welcome to clone my repository and extend it to your needs. Just drop in your Azure AD tenant name and native app ID into the code.
I think they just turned this on today - I was doing something unrelated with the Skype Web SDK samples and had to create a new Azure AD app, and noticed that there are two new preview features for receiving conversation updates and changing user information.
Now everything in the Github samples works for Skype For Business Online.

How to Authenticate and Authorize Asp.Net Web application through QuickBooks?

how to Authenticate and Authorize Asp.Net Web application through QuickBooks.
I want to integrate QuickBooks Accounts System in ASP.NET web Application I have successfully make developer account on quickbooks and make an app and got consumer key, consumer Secret and App Token and all URL's
Know I need some asp.net web api code snipped to successfully authenticate and authorize my web user's and than show there accounting detail
Please help me i Google alot but have no success.
I'm Strange this form is 0% active related to quickbooks API's or etc, after alot of struggling i found an answer of above mention question,
Download Quickbooks IPP.NET SDK it will provide you different classes for CURD.
var appToken = "";
var consumerKey = "";
var consumerSecret = "";
// the above 3 fields you can get when create your app on quickbook go to My app----> select youre app--->goto KEYS
var accessToken = "";
var accessTokenSecret = "";
// this two tookens you will get from URL on the same above page
var realmId = "1400728630"; //1400728630
// this is youre company ID which can be used when you create youre //company on freshbook
var serviceType = IntuitServicesType.QBO;
var validator = new OAuthRequestValidator(accessToken, accessTokenSecret, consumerKey, consumerSecret);
var context = new ServiceContext(appToken,realmId, serviceType, validator);
var service = new DataService(context);
try
{
Customer customer = new Customer();
//Mandatory Fields
customer.GivenName = "Mary";
customer.Title = "Ms.";
customer.MiddleName = "Jayne";
customer.FamilyName = "Cooper";
service.AddAsync(customer);
//service.Add(entity);
}catch(Exception ex)
{
System.Console.WriteLine(ex);
}

Resources