Skip to content

Update to MSAL 2.7 and use of Microsoft.Graph SDK #19

Merged
darrelmiller merged 22 commits intomicrosoftgraph:masterfrom
andrueastman:use-graph-sdk-and-update-msal
Mar 15, 2019
Merged

Update to MSAL 2.7 and use of Microsoft.Graph SDK #19
darrelmiller merged 22 commits intomicrosoftgraph:masterfrom
andrueastman:use-graph-sdk-and-update-msal

Conversation

@andrueastman
Copy link
Copy Markdown
Contributor

@andrueastman andrueastman commented Feb 7, 2019

Essentially, this PR makes the following updates: -

  • the MSAL dependencies are update to v2.7 from 1.1.4.
  • Updage Graph delta query calls to used the Graph SDKs(v1.1.12) rather than use Webclient calls Update to use Graph SDK #18
  • Helpers classes added to project to be similar to other console examples here
  • Fix for repeated Auth Prompts when running the example Repeated auth prompts #16
  • Minor improvements to use async rather than blocking calls and reading all configs at app start with Readme clarifications

Andrew Omondi added 4 commits February 6, 2019 12:44
- This checks deltas in mailFolders rather than drive
- Updated Readme for clarifications
- Removed Webclient dependencied to use the Graph API
-
…untime

- also abstracted away some hard coded values to config files.
@msftclas
Copy link
Copy Markdown

msftclas commented Feb 7, 2019

CLA assistant check
All CLA requirements met.

@jthake jthake requested review from jasonjoh and jmprieur February 7, 2019 16:16
@jthake
Copy link
Copy Markdown

jthake commented Feb 7, 2019

@jmprieur could you review this from an MSAL dotnet perspective. This is the first one we're updating from old MSAL and addig that helper classes to allow us to update to next version easily next time.

@jthake jthake requested review from darrelmiller and jthake February 7, 2019 16:17
Copy link
Copy Markdown

@jmprieur jmprieur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've left a few suggestions.
@andrueastman, would you mind giving me access to your repo (I'm assuming this is a private repo, as I was not able to see it):

  1. I'd like to see the code in Visual Studio
  2. I could propose a PR on top of yours

Regards
Jean-Marc

Comment thread Client/Client.cs Outdated
Comment thread Client/Client.cs Outdated
Comment thread Client/Client.cs Outdated

public MsalAuthenticationProvider(PublicClientApplication clientApplication, string[] scopes) {
_clientApplication = clientApplication;
_scopes = scopes;
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's weird that you pass the scopes in the MsalAuthenticationProvider? what will happen if your app wants to do a call to another Graph API (and therefore this requires more scopes) ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The idea would be to create a new GraphServiceClient and in effect MsalAuthenticationProvider objects with the right scopes and therefore make the calls to the other Graph API.

Copy link
Copy Markdown
Contributor

@darrelmiller darrelmiller Feb 8, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jmprieur In our actual AuthenticationProviders we allow scopes to be passed to the AuthenticationProvider via a "Request context" object. In .Net the request context is stored in the HttpRequestMessage.Properties dictionary and flows down the middleware pipe and is extracted by the AuthorizationProvider.

This will allow us to do incremental consent. There will be a fluent helper method on our GraphServiceClient to make it easy to pass scopes explicitly via the request and when we finally get permissions in the metadata we will embed these per request scopes into our code generated request builder.

/// </summary>
public async Task<string> GetTokenAsync()
{
if (_accessToken == null)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please never keep the access token in a variable
the right patter is to do:

try
{
 authResult = _clientApplication.AcquireTokenSilentAsync()
}
catch(MsalUiRequiredException)
{
 authResult = _clientApplication.AcquireTokenAsync()
}

The reason is if you keep the token and there is a need for incremental consent or conditional access (for example multiple factor auth), your GetTokenAsync will always fail.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This makes sense to me. Will action and resolve.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jmprieur Our goal here is not to try and support scenarios such as incremental consent and conditional access, but simply to provider a placeholder for the real AuthorizationProviders when they are ready. However, I agree that holding onto the token is not the best way of doing even this simple scenario.

Out of curiosity, is there an advantage to doing the try/catch over doing something like,

  if (_account == null) {
    authResult = _clientApplication.AquireTokenSilentAsync(_account);
 } else {
    authResult = _clientApplication.AquireTokenAsync();
    _account = authResult.Account
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@darrelmiller : there are many reasons why AcquireTokenSilentAsync would throw: that is if interaction is required from the user (password expired, conditional access needed, advanced security decides the user needs to re-sign-in etc …)

Comment thread README.md Outdated
1. In Solution Explorer, select the **App.config** project.
1. In Solution Explorer, select and edit the **App.config** in the ConsoleApplication project.

a. For the `AppPrincipalId` key, replace `To be filled in` with the application ID of your registered Azure application.
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

would that be the clientID?
Don't we want to be consistent with the authentication samples?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the suggestion to use the word clientID rather than AppPrincipalId ??

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes :-) This sample seems really old and a little confused. Sorry, I didn't realize we were throwing such a convoluted sample at you as your first one.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to have a look at the https://github.com/Azure-Samples/active-directory-coding-exercises which was done for the London event in Oct. @dkershaw10 : do you agree?

if (_accessToken == null)
{
AuthenticationResult authResult = null;
authResult = await _clientApplication.AcquireTokenAsync(_scopes);
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also this can throw. we need to handle the exception;

My proposal: let's work together on a class that you could reuse in all the samples.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also as you suggested, I'm happy to work together on this to make this class reusable.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jmprieur If we build an AuthorizationProvider class that works for all the samples, at what point are we reimplementing the classes we are doing in https://github.com/microsoftgraph/msgraph-sdk-dotnet-auth ? Perhaps we should focus on getting those completed faster, so the samples can take advantage of them?

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree @darrelmiller

@andrueastman
Copy link
Copy Markdown
Contributor Author

@jmprieur I have added you as collaborator but the repo is not private and can be found here.

Thanks for the comments. Working on resolving them.

@andrueastman andrueastman reopened this Feb 8, 2019
@jmprieur
Copy link
Copy Markdown

jmprieur commented Feb 8, 2019

thanks @andrueastman
For some reason, I had not found it :)

Comment thread Client/Client.cs Outdated
// - retry mechanism to be implemented
//
operation();
PublicClientApplication clientApplication = new PublicClientApplication(this.appPrincipalId, authority);
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We should rename appPrincipalId to clientId. And is appPrinicpalPassword used? This sample seems to use Interactive flow, not ClientCredentials flow.

Comment thread Client/Client.cs Outdated
/// <returns>Result from the Delta Query service.</returns>
public DeltaQueryResult DeltaQuery(
string entitySet,
public async Task<DeltaQueryResult> DeltaQueryAsync(
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We can talk about this on Monday. The original sample is actually trying to be more than just a sample and it is trying to create a generic client that can query any arbitrary entityset for deltaquery results. That type of functionality belongs in our core SDK, not in a sample. So, I agree with what you are doing here by using graphServiceClient to demo doing a DeltaQuery on a single entityset. However, to reduce the confusion, I think we should lift this code out of the Client class into the program class.

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

agreed, this sample is a little too confusing.

Copy link
Copy Markdown

@jthake jthake left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We will talk about this on Monday. But the readme instructions to get this working need updating and likely require some screen shots. So that people know what to do in portal.azure.com with Azure Active Directory to register the application.

Andrew Omondi added 3 commits February 11, 2019 11:04
- renamed AppPrincipalId to ClientId
- fixed issue of storing the token in the AuthProvider to properly acquire it  using the AcquireTokenSilentAsync function
- handled exceptions
- updated config file to rename AppPrincipalId to clientID
- changed Auth provider to handle local cache appropiately.
- Also made updated based on PR feedback.
Comment thread ConsoleApplication/app.config Outdated
<add key="TenantDomainName" value="To be filled in"/>
<!--Service principal credentials-->
<add key="AppPrincipalId" value="edd4904c-ac06-4f13-b8b5-9ec799e82bd3"/>
<add key="AppPrincipalId" value="To be filled in"/>
Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Move this to a separate .config file that is not checked in to the repo (added to .gitignore). This is to prevent inadvertently leaking your app ID.

Look at https://github.com/microsoftgraph/msgraph-training-aspnetmvcapp/tree/master/Demos/03-add-msgraph/graph-tutorial. In that sample, a separate PrivateSettings.config is used to hold OAuth settings, and is merged into Web.config by using this line:

<appSettings file="PrivateSettings.config">

Then, a copy of PrivateSettings.config, named PrivateSettings.config.example is added to the repo with placeholders, so devs can just rename the file and plug in their own app ID/secret.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this @jasonjoh,
I have made updates to this where the Readme has been updated to instruct the user to first rename the appsettings.json.example file and the appsettings.json been added to the .gitignore to prevent leaking of ones appID.

Copy link
Copy Markdown

@jmprieur jmprieur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a few more comments

Comment thread Client/Client.cs Outdated
Comment thread Client/Client.cs Outdated
/// </summary>
public async Task<string> GetTokenAsync()
{
if (_accessToken == null)
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@darrelmiller : there are many reasons why AcquireTokenSilentAsync would throw: that is if interaction is required from the user (password expired, conditional access needed, advanced security decides the user needs to re-sign-in etc …)

Andrew Omondi added 3 commits February 12, 2019 13:31
- used GraphServiceFactory 
- eliminated the client project as we are making graph calls directly now.
- moved stuff around to factor in changes.
Copy link
Copy Markdown

@jmprieur jmprieur left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.
I've made a few suggestions for improvements.
You probably want to fix the README.md, and discuss which headers you want to have.

Comment thread ConsoleApplication/ApplicationConfig.cs Outdated
Comment thread ConsoleApplication/DeltaQuery.cs Outdated
@@ -0,0 +1,230 @@
// <copyright file="DeltaQuery.cs" company="Microsoft">
Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You probably want to have the same copyright header on all files?
probably the MIT one? @jthake-msft ?

Comment thread ConsoleApplication/Helpers/GraphClientFactory.cs Outdated
Comment thread ConsoleApplication/Helpers/GraphClientFactory.cs
Comment thread README.md Outdated
Comment thread README.md Outdated
Comment thread README.md Outdated
Comment thread README.md Outdated
@andrueastman
Copy link
Copy Markdown
Contributor Author

Hey guys,

I have made some updates to the PR. Please check them out when you can :).

Thanks,
Andrew.

@jthake-msft @jmprieur @jasonjoh @darrelmiller

@jmprieur
Copy link
Copy Markdown

LGTM
Thanks for addressing the PR comments, @andrueastman !

@darrelmiller darrelmiller merged commit bafa885 into microsoftgraph:master Mar 15, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

6 participants