Skip to content

Commit c4f89c7

Browse files
authored
Merge pull request #78 from microsoftgraph/po/ExposeScopes
Return Login Context WIth Cumulative Scopes.
2 parents 155b8c9 + 72aef5f commit c4f89c7

11 files changed

+250
-19
lines changed

src/Authentication/Authentication/Cmdlets/ConnectGraph.cs

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,10 @@ namespace Microsoft.Graph.PowerShell.Authentication.Cmdlets
66
using Microsoft.Graph.Auth;
77
using Microsoft.Graph.PowerShell.Authentication.Helpers;
88
using Microsoft.Graph.PowerShell.Authentication.Models;
9+
using Microsoft.Identity.Client;
910
using System;
1011
using System.Collections.Generic;
12+
using System.Linq;
1113
using System.Management.Automation;
1214
using System.Net.Http;
1315
using System.Threading;
@@ -38,7 +40,7 @@ public class ConnectGraph : PSCmdlet
3840

3941
protected override void BeginProcessing()
4042
{
41-
validateParameters();
43+
ValidateParameters();
4244
base.BeginProcessing();
4345
}
4446

@@ -72,13 +74,15 @@ protected override void ProcessRecord()
7274
authConfig.CertificateName = CertificateName;
7375
}
7476

75-
// Save auth config to session state.
76-
SessionState.PSVariable.Set(Constants.GraphAuthConfigId, authConfig);
77-
7877
try
7978
{
8079
// Gets a static instance of IAuthenticationProvider when the client app hasn't changed.
8180
IAuthenticationProvider authProvider = AuthenticationHelpers.GetAuthProvider(authConfig);
81+
IClientApplicationBase clientApplication = null;
82+
if (ParameterSetName == Constants.UserParameterSet)
83+
clientApplication = (authProvider as DeviceCodeProvider).ClientApplication;
84+
else
85+
clientApplication = (authProvider as ClientCredentialProvider).ClientApplication;
8286

8387
// Incremental scope consent without re-instanciating the auth provider. We will use a static instance.
8488
GraphRequestContext graphRequestContext = new GraphRequestContext();
@@ -97,11 +101,23 @@ protected override void ProcessRecord()
97101
}
98102
}
99103
};
100-
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/me");
101-
httpRequestMessage.Properties.Add(typeof(GraphRequestContext).ToString(), graphRequestContext);
102104

103105
// Trigger consent.
106+
HttpRequestMessage httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "https://graph.microsoft.com/v1.0/me");
107+
httpRequestMessage.Properties.Add(typeof(GraphRequestContext).ToString(), graphRequestContext);
104108
authProvider.AuthenticateRequestAsync(httpRequestMessage).GetAwaiter().GetResult();
109+
110+
var accounts = clientApplication.GetAccountsAsync().GetAwaiter().GetResult();
111+
var account = accounts.FirstOrDefault();
112+
113+
JwtPayload jwtPayload = JwtHelpers.DecodeToObject<JwtPayload>(httpRequestMessage.Headers.Authorization?.Parameter);
114+
authConfig.Scopes = jwtPayload?.Scp?.Split(' ') ?? jwtPayload?.Roles;
115+
authConfig.TenantId = jwtPayload?.Tid ?? account?.HomeAccountId?.TenantId;
116+
authConfig.AppName = jwtPayload?.AppDisplayname;
117+
authConfig.Account = jwtPayload?.Upn ?? account?.Username;
118+
119+
// Save auth config to session state.
120+
SessionState.PSVariable.Set(Constants.GraphAuthConfigId, authConfig);
105121
}
106122
catch (AuthenticationException authEx)
107123
{
@@ -116,16 +132,14 @@ protected override void ProcessRecord()
116132
}
117133

118134
WriteObject("Welcome To Microsoft Graph!");
119-
// WriteObject(File.ReadAllText(".\\Art\\WelcomeText.txt"));
120-
// WriteObject(File.ReadAllText(".\\Art\\GRaphText.txt"));
121135
}
122136

123137
protected override void StopProcessing()
124138
{
125139
base.StopProcessing();
126140
}
127141

128-
private void validateParameters()
142+
private void ValidateParameters()
129143
{
130144
if (ParameterSetName == Constants.AppParameterSet)
131145
{
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
// ------------------------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.
3+
// ------------------------------------------------------------------------------
4+
5+
namespace Microsoft.Graph.PowerShell.Authentication.Cmdlets
6+
{
7+
using Microsoft.Graph.Auth;
8+
using Microsoft.Graph.PowerShell.Authentication.Helpers;
9+
using Microsoft.Graph.PowerShell.Authentication.Models;
10+
using System;
11+
using System.Collections.Generic;
12+
using System.Management.Automation;
13+
using System.Net.Http;
14+
using System.Threading;
15+
using System.Threading.Tasks;
16+
17+
[Cmdlet(VerbsCommon.Get, "MgContext", DefaultParameterSetName = Constants.UserParameterSet)]
18+
[OutputType(typeof(AuthConfig))]
19+
public class GetMGContext: PSCmdlet
20+
{
21+
protected override void BeginProcessing()
22+
{
23+
base.BeginProcessing();
24+
}
25+
26+
protected override void ProcessRecord()
27+
{
28+
base.ProcessRecord();
29+
// Get auth config from session state.
30+
PSVariable graphAuthVariable = SessionState.PSVariable.Get(Constants.GraphAuthConfigId);
31+
AuthConfig authConfig = graphAuthVariable?.Value as AuthConfig;
32+
Invoke<AuthConfig>();
33+
WriteObject(authConfig as AuthConfig);
34+
}
35+
36+
protected override void EndProcessing()
37+
{
38+
base.EndProcessing();
39+
}
40+
41+
protected override void StopProcessing()
42+
{
43+
base.StopProcessing();
44+
}
45+
}
46+
}
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
// ------------------------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.
3+
// ------------------------------------------------------------------------------
4+
namespace Microsoft.Graph.PowerShell.Authentication
5+
{
6+
public static class ErrorConstants
7+
{
8+
internal static class Codes
9+
{
10+
internal const string InvalidJWT = "invalidJWT";
11+
}
12+
13+
internal static class Message
14+
{
15+
internal const string InvalidJWT = "Invalid JWT access token.";
16+
}
17+
}
18+
}

src/Authentication/Authentication/Helpers/AuthenticationHelpers.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -100,7 +100,7 @@ private static X509Certificate2 GetCertificateByThumbprint(string CertificateThu
100100
.Find(X509FindType.FindByTimeValid, DateTime.Now, false)
101101
.Find(X509FindType.FindByThumbprint, CertificateThumbprint, false);
102102

103-
if (unexpiredCerts == null)
103+
if (unexpiredCerts.Count < 1)
104104
throw new Exception($"{CertificateThumbprint} certificate was not found or has expired.");
105105

106106
// Only return current cert.
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// ------------------------------------------------------------------------------
2+
// Copyright (c) Microsoft Corporation. All Rights Reserved. Licensed under the MIT License. See License in the project root for license information.
3+
// ------------------------------------------------------------------------------
4+
5+
namespace Microsoft.Graph.PowerShell.Authentication.Helpers
6+
{
7+
using Microsoft.Graph.Auth;
8+
using Microsoft.IdentityModel.Tokens;
9+
using Newtonsoft.Json;
10+
using Newtonsoft.Json.Linq;
11+
using System;
12+
using System.Collections.Generic;
13+
using System.IdentityModel.Tokens.Jwt;
14+
using System.Security.Claims;
15+
using System.Text;
16+
17+
/// <summary>
18+
/// A JwtHelpers class.
19+
/// </summary>
20+
internal static class JwtHelpers
21+
{
22+
/// <summary>
23+
/// Decodes a JWT token by extracting claims from the payload.
24+
/// </summary>
25+
/// <param name="jwToken">A JWT string.</param>
26+
internal static string Decode(string jwToken)
27+
{
28+
JwtSecurityTokenHandler jwtHandler = new JwtSecurityTokenHandler();
29+
if (jwtHandler.CanReadToken(jwToken))
30+
{
31+
JwtSecurityToken token = jwtHandler.ReadJwtToken(jwToken);
32+
JwtPayload jwtPayload = new JwtPayload(token.Claims);
33+
return jwtPayload.SerializeToJson();
34+
} else {
35+
return null;
36+
}
37+
}
38+
39+
/// <summary>
40+
/// Decodes a JWT token by extracting claims from the payload to an object of type T.
41+
/// </summary>
42+
/// <typeparam name="T">An object with properties of the JWT payload.</typeparam>
43+
/// <param name="jwToken">A JWT string.</param>
44+
internal static T DecodeToObject<T>(string jwtString)
45+
{
46+
try
47+
{
48+
string decodedJWT = Decode(jwtString);
49+
if (decodedJWT == null)
50+
return default(T);
51+
return JsonConvert.DeserializeObject<T>(decodedJWT);
52+
}
53+
catch (Exception ex)
54+
{
55+
throw new AuthenticationException(
56+
new Error
57+
{
58+
Code = ErrorConstants.Codes.InvalidJWT,
59+
Message = ErrorConstants.Message.InvalidJWT
60+
}, ex);
61+
}
62+
}
63+
}
64+
}

src/Authentication/Authentication/Microsoft.Graph.Authentication.csproj

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,10 +21,11 @@
2121
<PreLoadAssemblies Include="$(RepoTools)lib\System.Security.Cryptography.ProtectedData.dll" />
2222
</ItemGroup>
2323
<ItemGroup>
24-
<PackageReference Include="Microsoft.Graph.Auth" Version="1.0.0-preview.2" />
25-
<PackageReference Include="Microsoft.Graph.Core" Version="1.18.0" />
26-
<PackageReference Include="Microsoft.Identity.Client" Version="4.5.1" />
24+
<PackageReference Include="Microsoft.Graph.Auth" Version="1.0.0-preview.3" />
25+
<PackageReference Include="Microsoft.Graph.Core" Version="1.19.0" />
26+
<PackageReference Include="Microsoft.Identity.Client" Version="4.8.0" />
2727
<PackageReference Include="PowerShellStandard.Library" Version="5.1.0" />
28+
<PackageReference Include="System.IdentityModel.Tokens.Jwt" Version="5.6.0" />
2829
<PackageReference Include="System.Security.Cryptography.ProtectedData" Version="4.7.0" />
2930
</ItemGroup>
3031
<Target Name="CopyFiles" AfterTargets="Build">
Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
<?xml version="1.0" encoding="utf-8" ?>
2+
<Configuration>
3+
<ViewDefinitions>
4+
<View>
5+
<Name>AuthConfigView</Name>
6+
<ViewSelectedBy>
7+
<TypeName>Microsoft.Graph.PowerShell.Authentication.Models.AuthConfig</TypeName>
8+
</ViewSelectedBy>
9+
<TableControl>
10+
<TableHeaders>
11+
</TableHeaders>
12+
<TableRowEntries>
13+
<TableRowEntry>
14+
<TableColumnItems>
15+
<TableColumnItem>
16+
<PropertyName>AppName</PropertyName>
17+
</TableColumnItem>
18+
<TableColumnItem>
19+
<PropertyName>AuthType</PropertyName>
20+
</TableColumnItem>
21+
<TableColumnItem>
22+
<PropertyName>TenantId</PropertyName>
23+
</TableColumnItem>
24+
<TableColumnItem>
25+
<PropertyName>Account</PropertyName>
26+
</TableColumnItem>
27+
<TableColumnItem>
28+
<PropertyName>Scopes</PropertyName>
29+
</TableColumnItem>
30+
</TableColumnItems>
31+
</TableRowEntry>
32+
</TableRowEntries>
33+
</TableControl>
34+
</View>
35+
</ViewDefinitions>
36+
</Configuration>

src/Authentication/Authentication/Microsoft.Graph.Authentication.nuspec

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,8 @@
1717
</metadata>
1818
<files>
1919
<file src="Microsoft.Graph.Authentication.psd1" />
20+
<file src="Microsoft.Graph.Authentication.format.ps1xml" />
2021
<file src="Microsoft.Graph.Authentication.psm1" />
21-
<!--<file src="Graph.Authentication.psm1" />-->
2222
<!-- https://github.com/NuGet/Home/issues/3584 -->
2323
<file src="bin/Microsoft.Graph.Authentication.dll" target="bin" />
2424
<file src="bin/Microsoft.Graph.Authentication.deps.json" target="bin" />

src/Authentication/Authentication/Microsoft.Graph.Authentication.psd1

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ DotNetFrameworkVersion = '4.7.2'
6363
# TypesToProcess = @()
6464

6565
# Format files (.ps1xml) to be loaded when importing this module
66-
# FormatsToProcess = @()
66+
FormatsToProcess = './Microsoft.Graph.Authentication.Format.ps1xml'
6767

6868
# Modules to import as nested modules of the module specified in RootModule/ModuleToProcess
6969
# NestedModules = @()
@@ -72,13 +72,13 @@ DotNetFrameworkVersion = '4.7.2'
7272
FunctionsToExport = '*'
7373

7474
# Cmdlets to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no cmdlets to export.
75-
CmdletsToExport = 'Connect-Graph', 'Disconnect-Graph'
75+
CmdletsToExport = 'Connect-Graph', 'Disconnect-Graph', 'Get-MgContext'
7676

7777
# Variables to export from this module
78-
VariablesToExport = '*'
78+
# VariablesToExport = @()
7979

8080
# Aliases to export from this module, for best performance, do not use wildcards and do not delete the entry, use an empty array if there are no aliases to export.
81-
AliasesToExport = '*'
81+
AliasesToExport = @()
8282

8383
# DSC resources to export from this module
8484
# DscResourcesToExport = @()
@@ -95,7 +95,7 @@ PrivateData = @{
9595
PSData = @{
9696

9797
# Tags applied to this module. These help with module discovery in online galleries.
98-
Tags = 'Microsoft;Office365;Graph;PowerShell;GraphServiceClient;Outlook;OneDrive;AzureAD;GraphAPI;Productivity;SharePoint;Intune;SDK;'
98+
Tags = 'Microsoft','Office365','Graph','PowerShell','Teams','Outlook','OneDrive','AzureAD','GraphAPI','Productivity','SharePoint','Intune','SDK'
9999

100100
# A URL to the license for this module.
101101
LicenseUri = 'https://aka.ms/devservicesagreement'

src/Authentication/Authentication/Models/AuthConfig.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ public class AuthConfig
1818
public string[] Scopes { get; set; }
1919
public AuthenticationType AuthType { get; set; }
2020
public string CertificateName { get; set; }
21+
public string Account { get; set; }
22+
public string AppName { get; set; }
2123

2224
public AuthConfig()
2325
{

0 commit comments

Comments
 (0)