Skip to content
This repository was archived by the owner on Jul 22, 2024. It is now read-only.

Commit d1c7781

Browse files
idwilliams-2joelst
authored andcommitted
Authentication and test updates (#65)
* Added debug details to the Connect-PartnerCenter command. Also, performed minor refactoring on the test framework. * Consolidated the authentication constants into a single class.
1 parent 60480f3 commit d1c7781

8 files changed

Lines changed: 162 additions & 51 deletions

File tree

src/PartnerCenter.TestFramework/Network/HttpMockHandler.cs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,6 @@ namespace Microsoft.Store.PartnerCenter.TestFramework.Network
99
using System;
1010
using System.Collections.Generic;
1111
using System.IO;
12-
using System.Linq;
1312
using System.Net.Http;
1413
using System.Threading;
1514
using System.Threading.Tasks;
@@ -77,13 +76,12 @@ protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage
7776
{
7877
key = matcher.GetMatchingKey(request);
7978

80-
if (!records[key].Any())
79+
if(records[key] == null)
8180
{
8281
throw new ResponseNotFoundException($"Unable to locate a reponse for {key}");
8382
}
8483

85-
// TODO - We should not be dequeuing the record. It will cause issues with test that make the same call twice
86-
response = records[matcher.GetMatchingKey(request)].Dequeue().GetResponse();
84+
response = records[matcher.GetMatchingKey(request)].GetResponse();
8785
response.RequestMessage = request;
8886

8987
return response;
Lines changed: 8 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -1,23 +1,19 @@
11
// -----------------------------------------------------------------------
2-
// <copyright file="HttpContentType.cs" company="Microsoft">
2+
// <copyright file="HttpResponseRecords.cs" company="Microsoft">
33
// Copyright (c) Microsoft Corporation. All rights reserved.
44
// </copyright>
55
// -----------------------------------------------------------------------
66

77
namespace Microsoft.Store.PartnerCenter.TestFramework.Network
88
{
99
using System.Collections.Generic;
10-
using System.Linq;
1110

12-
/// <summary>
13-
///
14-
/// </summary>
1511
public sealed class HttpResponseRecords
1612
{
1713
/// <summary>
1814
/// A collection of HTTP operations.
1915
/// </summary>
20-
private readonly Dictionary<string, Queue<HttpResponseRecord>> sessionRecords;
16+
private readonly Dictionary<string, HttpResponseRecord> sessionRecords;
2117

2218
/// <summary>
2319
/// Provides the ability to map a request with it's corresponding response.
@@ -31,10 +27,10 @@ public sealed class HttpResponseRecords
3127
public HttpResponseRecords(IHttpRecordMatcher matcher)
3228
{
3329
this.matcher = matcher;
34-
sessionRecords = new Dictionary<string, Queue<HttpResponseRecord>>();
30+
sessionRecords = new Dictionary<string, HttpResponseRecord>();
3531
}
3632

37-
public Queue<HttpResponseRecord> this[string key]
33+
public HttpResponseRecord this[string key]
3834
{
3935
get => sessionRecords[key];
4036
set => sessionRecords[key] = value;
@@ -43,20 +39,17 @@ public Queue<HttpResponseRecord> this[string key]
4339
/// <summary>
4440
/// Gets the number of records contained in the collecion.
4541
/// </summary>
46-
public int Count => sessionRecords.Values.Select(q => q.Count).Sum();
42+
public int Count => sessionRecords.Count;
4743

4844
/// <summary>
4945
/// Gets all available records.
5046
/// </summary>
5147
/// <returns>All of the available records.</returns>
5248
public IEnumerable<HttpResponseRecord> GetAllEntities()
5349
{
54-
foreach (Queue<HttpResponseRecord> queues in sessionRecords.Values)
50+
foreach (HttpResponseRecord record in sessionRecords.Values)
5551
{
56-
while (queues.Count > 0)
57-
{
58-
yield return queues.Dequeue();
59-
}
52+
yield return record;
6053
}
6154
}
6255

@@ -66,14 +59,7 @@ public IEnumerable<HttpResponseRecord> GetAllEntities()
6659
/// <param name="record">The instance of the <see cref="HttpResponseRecord" /> class to be added.</param>
6760
public void Enqueue(HttpResponseRecord record)
6861
{
69-
string recordKey = matcher.GetMatchingKey(record);
70-
71-
if (!sessionRecords.ContainsKey(recordKey))
72-
{
73-
sessionRecords[recordKey] = new Queue<HttpResponseRecord>();
74-
}
75-
76-
sessionRecords[recordKey].Enqueue(record);
62+
sessionRecords[matcher.GetMatchingKey(record)] = record;
7763
}
7864
}
7965
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// -----------------------------------------------------------------------
2+
// <copyright file="AccountType.cs" company="Microsoft">
3+
// Copyright (c) Microsoft Corporation. All rights reserved.
4+
// </copyright>
5+
// -----------------------------------------------------------------------
6+
7+
namespace Microsoft.Store.PartnerCenter.PowerShell.Authentication
8+
{
9+
/// <summary>
10+
/// Provides access to common constant values used for authentication.
11+
/// </summary>
12+
internal static class AuthenticationConstants
13+
{
14+
/// <summary>
15+
/// The common endpoint used during authentication.
16+
/// </summary>
17+
public const string CommonEndpoint = "common";
18+
19+
/// <summary>
20+
/// The value for the redirect URI.
21+
/// </summary>
22+
public const string RedirectUriValue = "urn:ietf:wg:oauth:2.0:oob";
23+
}
24+
}

src/PowerShell/Commands/ConnectPartnerCenter.cs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,19 @@
77
namespace Microsoft.Store.PartnerCenter.PowerShell.Commands
88
{
99
using System;
10+
using System.Globalization;
1011
using System.Management.Automation;
1112
using System.Text.RegularExpressions;
1213
using Authentication;
1314
using Common;
1415
using Factories;
1516
using PartnerCenter.Models.Partners;
17+
using Properties;
1618

1719
/// <summary>
1820
/// Cmdlet to log into a Partner Center environment.
1921
/// </summary>
20-
[Cmdlet(VerbsCommunications.Connect, "PartnerCenter", DefaultParameterSetName = UserParameterSet)]
22+
[Cmdlet(VerbsCommunications.Connect, "PartnerCenter", DefaultParameterSetName = UserParameterSet)]
2123
[OutputType(typeof(PartnerContext))]
2224
public class ConnectPartnerCenter : PSCmdlet, IModuleAssemblyInitializer
2325
{
@@ -99,6 +101,8 @@ protected override void ProcessRecord()
99101
IPartner partnerOperations;
100102
OrganizationProfile profile;
101103

104+
WriteDebug(string.Format(CultureInfo.CurrentCulture, Resources.ConnectPartnerCenterBeginProcess, ParameterSetName));
105+
102106
if (ParameterSetName.Equals(AccessTokenParameterSet, StringComparison.InvariantCultureIgnoreCase))
103107
{
104108
account.Id = ApplicationId;
@@ -116,7 +120,7 @@ protected override void ProcessRecord()
116120
account.Type = AccountType.User;
117121
}
118122

119-
account.Properties[AzureAccountPropertyType.Tenant] = string.IsNullOrEmpty(TenantId) ? "common" : TenantId;
123+
account.Properties[AzureAccountPropertyType.Tenant] = string.IsNullOrEmpty(TenantId) ? AuthenticationConstants.CommonEndpoint : TenantId;
120124

121125
PartnerSession.Instance.Context = new PartnerContext
122126
{
@@ -130,9 +134,7 @@ protected override void ProcessRecord()
130134
d => WriteDebug(d),
131135
w => WriteWarning(w));
132136

133-
134-
// TODO -- This should be done for both Access Token and User
135-
if (PartnerSession.Instance.Context.Account.Type == AccountType.User)
137+
if (PartnerSession.Instance.Context.AuthenticationType == AuthenticationTypes.AppPlusUser)
136138
{
137139
partnerOperations = PartnerSession.Instance.ClientFactory.CreatePartnerOperations(d => WriteDebug(d));
138140
profile = partnerOperations.Profiles.OrganizationProfile.Get();

src/PowerShell/Commands/NewPartnerAccessToken.cs

Lines changed: 4 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -25,16 +25,6 @@ namespace Microsoft.Store.PartnerCenter.PowerShell.Commands
2525
[OutputType(typeof(AuthenticationResult))]
2626
public class NewPartnerAccessToken : PSCmdlet
2727
{
28-
/// <summary>
29-
/// The common endpoint used during authentication.
30-
/// </summary>
31-
private const string CommonEndpoint = "common";
32-
33-
/// <summary>
34-
/// The value for the redirect URI.
35-
/// </summary>
36-
private const string redirectUriValue = "urn:ietf:wg:oauth:2.0:oob";
37-
3828
/// <summary>
3929
/// The client used to perform HTTP operations.
4030
/// </summary>
@@ -119,7 +109,7 @@ protected override void ProcessRecord()
119109
clientId = ApplicationId;
120110
}
121111

122-
account.Properties[AzureAccountPropertyType.Tenant] = string.IsNullOrEmpty(TenantId) ? CommonEndpoint : TenantId;
112+
account.Properties[AzureAccountPropertyType.Tenant] = string.IsNullOrEmpty(TenantId) ? AuthenticationConstants.CommonEndpoint : TenantId;
123113
environment = PartnerEnvironment.PublicEnvironments[Environment];
124114

125115
client = new PartnerServiceClient(httpClient);
@@ -166,14 +156,14 @@ protected override void ProcessRecord()
166156
using (WindowsFormsWebAuthenticationDialog dialog = new WindowsFormsWebAuthenticationDialog(null))
167157
{
168158
authorizationResult = dialog.AuthenticateAAD(
169-
new Uri($"{environment.ActiveDirectoryAuthority}{account.Properties[AzureAccountPropertyType.Tenant]}/oauth2/authorize?resource={HttpUtility.UrlEncode(Resource)}&client_id={clientId}&response_type=code&haschrome=1&redirect_uri={HttpUtility.UrlEncode(redirectUriValue)}&response_mode=form_post&prompt=login"),
170-
new Uri(redirectUriValue));
159+
new Uri($"{environment.ActiveDirectoryAuthority}{account.Properties[AzureAccountPropertyType.Tenant]}/oauth2/authorize?resource={HttpUtility.UrlEncode(Resource)}&client_id={clientId}&response_type=code&haschrome=1&redirect_uri={HttpUtility.UrlEncode(AuthenticationConstants.RedirectUriValue)}&response_mode=form_post&prompt=login"),
160+
new Uri(AuthenticationConstants.RedirectUriValue));
171161
}
172162

173163
authResult = client.AcquireTokenByAuthorizationCodeAsync(
174164
authority,
175165
resource,
176-
new Uri(redirectUriValue),
166+
new Uri(AuthenticationConstants.RedirectUriValue),
177167
authorizationResult.Code,
178168
clientId,
179169
Credential?.Password.ConvertToString()).GetAwaiter().GetResult();

src/PowerShell/Factories/AuthenticationFactory.cs

Lines changed: 45 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -13,17 +13,13 @@ namespace Microsoft.Store.PartnerCenter.PowerShell.Factories
1313
using System.Security.Claims;
1414
using Authentication;
1515
using IdentityModel.Clients.ActiveDirectory;
16+
using Properties;
1617

1718
/// <summary>
1819
/// Factory used to perform authentication operations.
1920
/// </summary>
2021
public class AuthenticationFactory : IAuthenticationFactory
2122
{
22-
/// <summary>
23-
/// The value for the redirect URI.
24-
/// </summary>
25-
private const string redirectUriValue = "urn:ietf:wg:oauth:2.0:oob";
26-
2723
/// <summary>
2824
/// Acquires the security token from the authority.
2925
/// </summary>
@@ -64,12 +60,30 @@ public AuthenticationToken Authenticate(PartnerContext context, Action<string> d
6460

6561
context.AuthenticationType = claim == null ? Authentication.AuthenticationTypes.AppOnly : Authentication.AuthenticationTypes.AppPlusUser;
6662

63+
debugAction(
64+
string.Format(
65+
CultureInfo.CurrentCulture,
66+
Resources.AuthenticateAccessTokenTrace,
67+
expiration.ToString(CultureInfo.CurrentCulture),
68+
context.Account.Properties[AzureAccountPropertyType.Tenant],
69+
context.Account.Properties[AzureAccountPropertyType.UserIdentifier],
70+
claim?.Value));
71+
6772
return new AuthenticationToken(
6873
context.Account.Properties[AzureAccountPropertyType.AccessToken],
6974
expiration);
7075
}
7176
else if (context.Account.Type == AccountType.ServicePrincipal)
7277
{
78+
debugAction(
79+
string.Format(
80+
CultureInfo.CurrentCulture,
81+
Resources.AuthenticateServicePrincipalTrace,
82+
environment.ActiveDirectoryAuthority,
83+
context.Account.Id,
84+
environment.AzureAdGraphEndpoint,
85+
context.Account.Properties[AzureAccountPropertyType.Tenant]));
86+
7387
authResult = authContext.AcquireTokenAsync(
7488
environment.AzureAdGraphEndpoint,
7589
new ClientCredential(
@@ -81,6 +95,13 @@ public AuthenticationToken Authenticate(PartnerContext context, Action<string> d
8195
else if (!context.Account.Properties.ContainsKey(AzureAccountPropertyType.UserIdentifier))
8296
{
8397
#if NETSTANDARD
98+
debugAction(
99+
string.Format(
100+
CultureInfo.CurrentCulture,
101+
Resources.AuthenticateDeviceCodeTrace,
102+
context.ApplicationId,
103+
environment.PartnerCenterEndpoint));
104+
84105
DeviceCodeResult deviceCodeResult = authContext.AcquireDeviceCodeAsync(
85106
environment.PartnerCenterEndpoint,
86107
context.ApplicationId).ConfigureAwait(false).GetAwaiter().GetResult();
@@ -89,10 +110,19 @@ public AuthenticationToken Authenticate(PartnerContext context, Action<string> d
89110

90111
authResult = authContext.AcquireTokenByDeviceCodeAsync(deviceCodeResult).ConfigureAwait(false).GetAwaiter().GetResult();
91112
#else
113+
debugAction(
114+
string.Format(
115+
CultureInfo.CurrentCulture,
116+
Resources.AuthenticateAuthorizationCodeTrace,
117+
context.ApplicationId,
118+
environment.ActiveDirectoryAuthority,
119+
AuthenticationConstants.RedirectUriValue,
120+
environment.PartnerCenterEndpoint));
121+
92122
authResult = authContext.AcquireTokenAsync(
93123
environment.PartnerCenterEndpoint,
94124
context.ApplicationId,
95-
new Uri(redirectUriValue),
125+
new Uri(AuthenticationConstants.RedirectUriValue),
96126
new PlatformParameters(PromptBehavior.Always),
97127
UserIdentifier.AnyUser).ConfigureAwait(false).GetAwaiter().GetResult();
98128
#endif
@@ -104,6 +134,15 @@ public AuthenticationToken Authenticate(PartnerContext context, Action<string> d
104134
}
105135
else
106136
{
137+
debugAction(
138+
string.Format(
139+
CultureInfo.CurrentCulture,
140+
Resources.AuthenticateSilentTrace,
141+
context.ApplicationId,
142+
environment.ActiveDirectoryAuthority,
143+
environment.PartnerCenterEndpoint,
144+
context.Account.Id));
145+
107146
authResult = authContext.AcquireTokenSilentAsync(
108147
environment.PartnerCenterEndpoint,
109148
context.ApplicationId,

src/PowerShell/Properties/Resources.Designer.cs

Lines changed: 54 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)