├── Template
├── .gitignore
├── jquery.min.js.gz
├── popper.min.js.gz
├── bootstrap.min.css.gz
├── bootstrap.min.js.gz
├── bootstrap-table.min.js.gz
├── bootstrap-table.min.css.gz
├── responsivetemplate.html
├── ReportBase.js
├── ProcessTemplate.ps1
├── TemplateManager.cs
├── ReportMain.js
└── ReportBase.css
├── LICENSE.md
├── pingcastle.ico
├── packages.config
├── RESTServices
├── IAzureService.cs
├── ClientIDs.cs
├── AzureServiceAttribute.cs
├── EndPointAttribute.cs
├── Azure
│ ├── AzureADConnectApi.cs
│ ├── MicrosoftGraph.cs
│ └── ManagementApi.cs
├── O365
│ └── O365Api.cs
└── RESTClientBase.cs
├── PingCastleCloudException.cs
├── Tokens
├── JwtHeader.cs
├── ChallengeResponse.cs
├── JwtPayload.cs
├── TokenCache.cs
├── Token.cs
├── JwtToken.cs
└── CookieManager.cs
├── App.config
├── Credentials
├── UserCredential.cs
├── PRTCredential.cs
├── IAzureCredential.cs
├── CredentialBase.cs
└── CertificateCredential.cs
├── PingCastleCloud.sln
├── Rules
├── UserConsentCompanyData.cs
├── UserRegisterApplications.cs
├── GuestUserAccessRestriction2.cs
├── GuestUserAccessRestriction1.cs
├── ADConnectVersion1.cs
├── ADConnectVersion.cs
├── CustomRulesSettings.cs
├── RuleBase.cs
├── RuleSet.cs
└── RuleDescription.Designer.cs
├── Logs
├── LoggingHandler.cs
└── SazGenerator.cs
├── PublicServices
├── UserRealmCTRequest.cs
├── UserRealmV1.cs
├── UserRealmV2.cs
├── UserRealmSRF.cs
├── UserRealmCT.cs
├── OpenIDConfiguration.cs
├── PublicService.cs
└── TenantBrandingInfo.cs
├── Constants.cs
├── Properties
└── AssemblyInfo.cs
├── CreateSecureAppCert.ps1
├── README.md
├── UI
└── AuthenticationDialog.Designer.cs
├── Common
├── JsonSerialization.cs
└── HttpClientHelper.cs
├── .gitignore
├── PingCastleCloud.csproj
├── Export
└── ExportAsGuest.cs
├── License.cs
└── Data
└── HealthCheckCloudData.cs
/Template/.gitignore:
--------------------------------------------------------------------------------
1 | *.min.css
2 | *.min.js
3 | *.gz
4 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netwrix/PingCastleCloud/HEAD/LICENSE.md
--------------------------------------------------------------------------------
/pingcastle.ico:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netwrix/PingCastleCloud/HEAD/pingcastle.ico
--------------------------------------------------------------------------------
/Template/jquery.min.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netwrix/PingCastleCloud/HEAD/Template/jquery.min.js.gz
--------------------------------------------------------------------------------
/Template/popper.min.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netwrix/PingCastleCloud/HEAD/Template/popper.min.js.gz
--------------------------------------------------------------------------------
/Template/bootstrap.min.css.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netwrix/PingCastleCloud/HEAD/Template/bootstrap.min.css.gz
--------------------------------------------------------------------------------
/Template/bootstrap.min.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netwrix/PingCastleCloud/HEAD/Template/bootstrap.min.js.gz
--------------------------------------------------------------------------------
/Template/bootstrap-table.min.js.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netwrix/PingCastleCloud/HEAD/Template/bootstrap-table.min.js.gz
--------------------------------------------------------------------------------
/Template/bootstrap-table.min.css.gz:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/netwrix/PingCastleCloud/HEAD/Template/bootstrap-table.min.css.gz
--------------------------------------------------------------------------------
/packages.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/RESTServices/IAzureService.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 |
13 | namespace PingCastleCloud.RESTServices.Azure
14 | {
15 | public interface IAzureService
16 | {
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/Template/responsivetemplate.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 | <%=Header%>
12 |
13 |
14 |
15 |
16 | <%=Body%>
17 |
18 | <%=Footer%>
19 |
20 |
21 |
--------------------------------------------------------------------------------
/PingCastleCloudException.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using System.Text;
11 |
12 | namespace PingCastleCloud
13 | {
14 | class PingCastleCloudException : Exception
15 | {
16 | public PingCastleCloudException(string message)
17 | : base(message)
18 | {
19 | }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/RESTServices/ClientIDs.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 |
13 | namespace PingCastleCloud.RESTServices.Azure
14 | {
15 | public class ClientIDs
16 | {
17 | public static readonly Guid GraphAPI = new Guid("1b730954-1685-4b74-9bfd-dac224a7b894");
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/Tokens/JwtHeader.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.Common;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 |
14 | namespace PingCastleCloud.Tokens
15 | {
16 | public class JwtHeader : JsonSerialization
17 | {
18 | public string alg { get; set; }
19 | public string typ { get; set; }
20 | public string x5t { get; set; }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/Tokens/ChallengeResponse.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.Common;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Runtime.Serialization;
12 | using System.Text;
13 | using System.Threading.Tasks;
14 |
15 | namespace PingCastleCloud.RESTServices
16 | {
17 | [DataContractAttribute]
18 | public class ChallengeResponse : JsonSerialization
19 | {
20 | [DataMember]
21 | public string Nonce { get; set; }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/App.config:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/Credentials/UserCredential.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.RESTServices.Azure;
8 | using PingCastleCloud.Tokens;
9 | using System;
10 | using System.Collections.Generic;
11 | using System.Linq;
12 | using System.Text;
13 | using System.Threading.Tasks;
14 |
15 | namespace PingCastleCloud.Credentials
16 | {
17 | public class UserCredential : CredentialBase
18 | {
19 | public UserCredential() : base()
20 | {
21 | }
22 |
23 | public UserCredential(string tenantid) : base(tenantid)
24 | {
25 | }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/Credentials/PRTCredential.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.RESTServices.Azure;
8 | using PingCastleCloud.Tokens;
9 | using System;
10 | using System.Collections.Generic;
11 | using System.Linq;
12 | using System.Text;
13 | using System.Threading.Tasks;
14 |
15 | namespace PingCastleCloud.Credentials
16 | {
17 |
18 | public class PRTCredential : CredentialBase
19 | {
20 | public PRTCredential() : base()
21 | {
22 | }
23 |
24 | public PRTCredential(string tenantid) : base(tenantid)
25 | {
26 | }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/Credentials/IAzureCredential.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.RESTServices.Azure;
8 | using PingCastleCloud.Tokens;
9 | using System;
10 | using System.Collections.Generic;
11 | using System.Linq;
12 | using System.Text;
13 | using System.Threading.Tasks;
14 |
15 | namespace PingCastleCloud.Credentials
16 | {
17 | public interface IAzureCredential
18 | {
19 | string Tenantid { get; }
20 | string TenantidToQuery { get; set; }
21 | Task GetToken() where T : IAzureService;
22 | Token LastTokenQueried { get; }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/Tokens/JwtPayload.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.Common;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 |
14 | namespace PingCastleCloud.Tokens
15 | {
16 | public class JwtPayload : JsonSerialization
17 | {
18 | public string aud { get; set; }
19 | public long exp { get; set; }
20 | public string iss { get; set; }
21 |
22 |
23 | public string jti { get; set; }
24 | public long nbf { get; set; }
25 | public string sub { get; set; }
26 | public long iat { get; set; }
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/PingCastleCloud.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 2012
4 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PingCastleCloud", "PingCastleCloud.csproj", "{138C3C69-1245-4BBA-87B5-075E7140B826}"
5 | EndProject
6 | Global
7 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
8 | Debug|Any CPU = Debug|Any CPU
9 | Release|Any CPU = Release|Any CPU
10 | EndGlobalSection
11 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
12 | {138C3C69-1245-4BBA-87B5-075E7140B826}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
13 | {138C3C69-1245-4BBA-87B5-075E7140B826}.Debug|Any CPU.Build.0 = Debug|Any CPU
14 | {138C3C69-1245-4BBA-87B5-075E7140B826}.Release|Any CPU.ActiveCfg = Release|Any CPU
15 | {138C3C69-1245-4BBA-87B5-075E7140B826}.Release|Any CPU.Build.0 = Release|Any CPU
16 | EndGlobalSection
17 | GlobalSection(SolutionProperties) = preSolution
18 | HideSolutionNode = FALSE
19 | EndGlobalSection
20 | EndGlobal
21 |
--------------------------------------------------------------------------------
/Rules/UserConsentCompanyData.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.Data;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 |
14 | namespace PingCastleCloud.Rules
15 | {
16 | [RuleModel("UserConsentCompanyData")]
17 | [RuleComputation(RuleComputationType.TriggerOnPresence, 5)]
18 | [RuleMaturityLevel(2)]
19 | public class UserConsentCompanyData : RuleBase
20 | {
21 | protected override int? AnalyzeDataNew(HealthCheckCloudData healthCheckCloudData)
22 | {
23 | if (healthCheckCloudData.UsersPermissionToUserConsentToAppEnabled == true)
24 | {
25 | AddRawDetail("true");
26 | }
27 | return null;
28 | }
29 |
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Rules/UserRegisterApplications.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.Data;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 |
14 | namespace PingCastleCloud.Rules
15 | {
16 | [RuleModel("UserRegisterApplications")]
17 | [RuleComputation(RuleComputationType.TriggerOnPresence, 5)]
18 | [RuleMaturityLevel(2)]
19 | public class UserRegisterApplications : RuleBase
20 | {
21 | protected override int? AnalyzeDataNew(HealthCheckCloudData healthCheckCloudData)
22 | {
23 | if (healthCheckCloudData.UsersPermissionToCreateLOBAppsEnabled == true)
24 | {
25 | AddRawDetail("true");
26 | }
27 | return null;
28 | }
29 |
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Template/ReportBase.js:
--------------------------------------------------------------------------------
1 | $(function () {
2 | $(window).scroll(function () {
3 | if ($(window).scrollTop() >= 70) {
4 | $('.information-bar').removeClass('hidden');
5 | $('.information-bar').fadeIn('fast');
6 | } else {
7 | $('.information-bar').fadeOut('fast');
8 | }
9 | });
10 | });
11 |
12 | document.addEventListener('DOMContentLoaded', function () {
13 |
14 | $('.div_model').on('click', function (e) {
15 | $('.div_model').not(this).popover('hide');
16 | });
17 |
18 | new bootstrap.Tooltip(document.body, {
19 | selector: '.has-tooltip'
20 | });
21 |
22 | });
23 |
24 | function getData(dataSelect) {
25 | try {
26 | const inlineJsonElement = document.querySelector(
27 | 'script[type="application/json"][data-pingcastle-selector="' + dataSelect + '"]'
28 | );
29 | const data = JSON.parse(inlineJsonElement.textContent);
30 | return data;
31 | } catch (err) {
32 | console.error("Couldn't read JSON data from " + dataSelect, err);
33 | }
34 | }
--------------------------------------------------------------------------------
/Rules/GuestUserAccessRestriction2.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.Data;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 |
14 | namespace PingCastleCloud.Rules
15 | {
16 | [RuleModel("GuestUserAccessRestriction2")]
17 | [RuleComputation(RuleComputationType.TriggerOnPresence, 0)]
18 | [RuleMaturityLevel(4)]
19 | public class GuestUserAccessRestriction2 : RuleBase
20 | {
21 | protected override int? AnalyzeDataNew(HealthCheckCloudData healthCheckCloudData)
22 | {
23 | if (string.Equals(healthCheckCloudData.PolicyGuestUserRoleId, "10dae51f-b6af-4016-8d66-8c2a99b929b3", StringComparison.OrdinalIgnoreCase))
24 | {
25 | AddRawDetail(healthCheckCloudData.PolicyGuestUserRoleId);
26 | }
27 | return null;
28 | }
29 |
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Rules/GuestUserAccessRestriction1.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.Data;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 |
14 | namespace PingCastleCloud.Rules
15 | {
16 | [RuleModel("GuestUserAccessRestriction1")]
17 | [RuleComputation(RuleComputationType.TriggerOnPresence, 25)]
18 | [RuleMaturityLevel(1)]
19 | public class GuestUserAccessRestriction1 : RuleBase
20 | {
21 | protected override int? AnalyzeDataNew(HealthCheckCloudData healthCheckCloudData)
22 | {
23 | if (string.Equals(healthCheckCloudData.PolicyGuestUserRoleId, "a0b1b346-4d3e-4e8b-98f8-753987be4970", StringComparison.OrdinalIgnoreCase))
24 | {
25 | AddRawDetail(healthCheckCloudData.PolicyGuestUserRoleId);
26 | }
27 | return null;
28 | }
29 |
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/Logs/LoggingHandler.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using System.Net.Http;
11 | using System.Text;
12 | using System.Threading;
13 | using System.Threading.Tasks;
14 |
15 | namespace PingCastleCloud.Logs
16 | {
17 | public class LoggingHandler : DelegatingHandler
18 | {
19 | private SazGenerator _sazGenerator;
20 |
21 | public LoggingHandler(SazGenerator sazGenerator, HttpMessageHandler innerHandler)
22 | : base(innerHandler)
23 | {
24 | _sazGenerator = sazGenerator;
25 | }
26 |
27 | protected override async Task SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
28 | {
29 | int num = _sazGenerator.RecordBeginQuery(request);
30 |
31 | HttpResponseMessage response = await base.SendAsync(request, cancellationToken);
32 |
33 | _sazGenerator.RecordEndQuery(num, response);
34 |
35 | return response;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/Tokens/TokenCache.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using System;
8 | using System.Collections.Generic;
9 | using System.IO;
10 | using System.Linq;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 |
14 | namespace PingCastleCloud.Tokens
15 | {
16 | public class TokenCache
17 | {
18 | const string DirectoryName = "Cache";
19 | public static List GetTokens()
20 | {
21 | var output = new List();
22 | foreach (var file in Directory.EnumerateFiles(DirectoryName, "*.json"))
23 | {
24 | output.Add(Token.LoadFromString(File.ReadAllText(file)));
25 | }
26 | return output;
27 | }
28 |
29 | public static void Save(Token token)
30 | {
31 | if (!Directory.Exists(DirectoryName))
32 | Directory.CreateDirectory(DirectoryName);
33 | File.WriteAllText(Path.Combine(DirectoryName, token .resource.Replace("https://", "").Replace("/", "") + "-" + Guid.NewGuid() + ".json"), token.ToJsonString());
34 | }
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/PublicServices/UserRealmCTRequest.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.Common;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Runtime.Serialization;
12 | using System.Text;
13 | using System.Threading.Tasks;
14 |
15 | namespace PingCastleCloud.PublicServices
16 | {
17 | [DataContractAttribute]
18 | public class UserRealmCTRequest : JsonSerialization
19 | {
20 | [DataMember]
21 | public string username { get; set; }
22 | [DataMember]
23 | public bool isOtherIdpSupported { get; set; }
24 | [DataMember]
25 | public bool checkPhones { get; set; }
26 | [DataMember]
27 | public bool isRemoteNGCSupported { get; set; }
28 | [DataMember]
29 | public bool isCookieBannerShown { get; set; }
30 | [DataMember]
31 | public bool isFidoSupported { get; set; }
32 | [DataMember]
33 | public string originalRequest { get; set; }
34 | [DataMember]
35 | public string flowToken { get; set; }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/PublicServices/UserRealmV1.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.Common;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Runtime.Serialization;
12 | using System.Text;
13 | using System.Threading.Tasks;
14 |
15 | namespace PingCastleCloud.PublicServices
16 | {
17 | [DataContractAttribute]
18 | public class UserRealmV1 : JsonSerialization
19 | {
20 | [DataMember]
21 | public string ver { get; set; }
22 | [DataMember]
23 | public string account_type { get; set; }
24 | [DataMember]
25 | public string domain_name { get; set; }
26 | [DataMember]
27 | public string federation_protocol { get; set; }
28 | [DataMember]
29 | public string federation_metadata_url { get; set; }
30 | [DataMember]
31 | public string federation_active_auth_url { get; set; }
32 | [DataMember]
33 | public string cloud_instance_name { get; set; }
34 | [DataMember]
35 | public string cloud_audience_urn { get; set; }
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/PublicServices/UserRealmV2.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.Common;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Runtime.Serialization;
12 | using System.Text;
13 | using System.Threading.Tasks;
14 |
15 | namespace PingCastleCloud.PublicServices
16 | {
17 | [DataContractAttribute]
18 | public class UserRealmV2 : JsonSerialization
19 | {
20 | [DataMember]
21 | public string NameSpaceType { get; set; }
22 | [DataMember]
23 | public string federation_protocol { get; set; }
24 | [DataMember]
25 | public string Login { get; set; }
26 | [DataMember]
27 | public string AuthURL { get; set; }
28 | [DataMember]
29 | public string DomainName { get; set; }
30 | [DataMember]
31 | public string FederationBrandName { get; set; }
32 | [DataMember]
33 | public List TenantBrandingInfo { get; set; }
34 | [DataMember]
35 | public string cloud_instance_name { get; set; }
36 | }
37 |
38 |
39 | }
40 |
--------------------------------------------------------------------------------
/Rules/ADConnectVersion1.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.Data;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 |
14 | namespace PingCastleCloud.Rules
15 | {
16 | [RuleModel("ADConnectVersion1")]
17 | [RuleComputation(RuleComputationType.TriggerOnPresence, 5)]
18 | [RuleMaturityLevel(2)]
19 | public class ADConnectVersion1 : RuleBase
20 | {
21 | protected override int? AnalyzeDataNew(HealthCheckCloudData healthCheckCloudData)
22 | {
23 | if (healthCheckCloudData.ProvisionDirectorySynchronizationStatus == "Enabled")
24 | {
25 | Version v;
26 | if (Version.TryParse(healthCheckCloudData.ProvisionDirSyncClientVersion, out v))
27 | {
28 | if (v.Major == 1)
29 | {
30 | AddRawDetail(healthCheckCloudData.ProvisionDirSyncClientVersion);
31 | }
32 | }
33 | }
34 | return null;
35 | }
36 |
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/PublicServices/UserRealmSRF.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.Common;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Runtime.Serialization;
12 | using System.Text;
13 | using System.Threading.Tasks;
14 |
15 | namespace PingCastleCloud.PublicServices
16 | {
17 | [DataContractAttribute]
18 | public class UserRealmSRF : JsonSerialization
19 | {
20 | [DataMember]
21 | public int State { get; set; }
22 | [DataMember]
23 | public int UserState { get; set; }
24 | [DataMember]
25 | public string Login { get; set; }
26 | [DataMember]
27 | public string NameSpaceType { get; set; }
28 | [DataMember]
29 | public string DomainName { get; set; }
30 | [DataMember]
31 | public int FederationGlobalVersion { get; set; }
32 | [DataMember]
33 | public string AuthURL { get; set; }
34 | [DataMember]
35 | public string FederationBrandName { get; set; }
36 | [DataMember]
37 | public string CloudInstanceName { get; set; }
38 | [DataMember]
39 | public string CloudInstanceIssuerUri { get; set; }
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/RESTServices/AzureServiceAttribute.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 | using System.Reflection;
13 |
14 | namespace PingCastleCloud.RESTServices.Azure
15 | {
16 | public class AzureServiceAttribute : Attribute
17 | {
18 | public AzureServiceAttribute(string ClientID, string Resource, string RedirectUri = Constants.redirectUri)
19 | {
20 | this.ClientID = Guid.Parse(ClientID);
21 | this.Resource = Resource;
22 | this.RedirectUri = RedirectUri;
23 | }
24 | public Guid ClientID { get; set; }
25 | public string Resource { get; set; }
26 | public string RedirectUri { get; set; }
27 |
28 | public static AzureServiceAttribute GetAzureServiceAttribute() where T : IAzureService
29 | {
30 | AzureServiceAttribute[] attrs = (AzureServiceAttribute[])typeof(T).GetCustomAttributes(typeof(AzureServiceAttribute));
31 | if (attrs.Length > 0)
32 | return attrs[0];
33 | throw new ApplicationException("no service attribute found");
34 | }
35 | }
36 |
37 |
38 | }
39 |
--------------------------------------------------------------------------------
/Tokens/Token.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.Common;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.IO;
11 | using System.Linq;
12 | using System.Runtime.Serialization;
13 | using System.Runtime.Serialization.Json;
14 | using System.Text;
15 | using System.Threading.Tasks;
16 |
17 | namespace PingCastleCloud.Tokens
18 | {
19 | public class Token : JsonSerialization
20 | {
21 |
22 | public string token_type { get; set; }
23 |
24 | public string scope { get; set; }
25 |
26 | public uint expires_in { get; set; }
27 |
28 | public uint ext_expires_in { get; set; }
29 |
30 | public uint expires_on { get; set; }
31 |
32 | public uint not_before { get; set; }
33 |
34 |
35 | public string resource { get; set; }
36 |
37 | public string access_token { get; set; }
38 |
39 | public string refresh_token { get; set; }
40 |
41 | public string id_token { get; set; }
42 |
43 | public JwtToken ToJwtToken()
44 | {
45 | return JwtToken.LoadFromBase64String(access_token.Split('.')[1]);
46 | }
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/RESTServices/EndPointAttribute.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 | using System.Reflection;
13 |
14 | namespace PingCastleCloud.RESTServices.Azure
15 | {
16 | public class EndPointAttribute : Attribute
17 | {
18 | public EndPointAttribute(string Authorize, string Token)
19 | {
20 | this.AuthorizeEndPoint = Authorize;
21 | this.TokenEndPoint = Token;
22 | }
23 |
24 | public string AuthorizeEndPoint { get; private set; }
25 | public string TokenEndPoint { get; private set; }
26 |
27 | public static EndPointAttribute GetEndPointAttribute() where T : IAzureService
28 | {
29 | EndPointAttribute[] attrs = (EndPointAttribute[])typeof(T).GetCustomAttributes(typeof(EndPointAttribute));
30 | if (attrs.Length > 0)
31 | return attrs[0];
32 | return DefaultEndPointAttribute();
33 | }
34 |
35 | private static EndPointAttribute DefaultEndPointAttribute()
36 | {
37 | return new EndPointAttribute(Constants.OAuth2AuthorizeEndPoint, Constants.OAuth2TokenEndPoint);
38 | }
39 | }
40 |
41 |
42 | }
43 |
--------------------------------------------------------------------------------
/Constants.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 |
13 | namespace PingCastleCloud
14 | {
15 | public class Constants
16 | {
17 | public const string LoginEndPoint = "https://login.microsoftonline.com/";
18 | public const string OAuth2AuthorizeEndPoint = "https://login.microsoftonline.com/common/oauth2/authorize";
19 | public const string OAuth2TokenEndPoint = "https://login.microsoftonline.com/common/oauth2/token";
20 | public const string OAuth2NativeClientEndPoint = "urn:ietf:wg:oauth:2.0:oob";//"https://login.microsoftonline.com/common/oauth2/nativeclient";
21 | public const string UserRealmEndpoint = "https://login.microsoftonline.com/common/userrealm/";
22 | public const string UserRealmSRFEndpoint = "https://login.microsoftonline.com/GetUserRealm.srf?login=";
23 | public const string UserRealmCTEndpoint = "https://login.microsoftonline.com/common/GetCredentialType";
24 | public const string OpenIdConfigurationEndpoint = "https://login.windows.net/xxxxx/.well-known/openid-configuration";
25 | public const string ProvisionningEndpoint = "https://provisioningapi.microsoftonline.com/provisioningwebservice.svc";
26 | public const string redirectUri = "urn:ietf:wg:oauth:2.0:oob";
27 | public const string OrganisationsNativeClient = "https://login.microsoftonline.com/organizations/oauth2/nativeclient";
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/Template/ProcessTemplate.ps1:
--------------------------------------------------------------------------------
1 | # thanks Mathias ! (@IISResetMe)
2 |
3 | function New-Gzip
4 | {
5 | param(
6 | [Parameter(Mandatory = $true)]
7 | [ValidateScript({Test-Path $_ -PathType Leaf})]
8 | [string]$Path
9 | )
10 |
11 | if((Resolve-Path $Path).Provider.Name -ne 'FileSystem'){
12 | Write-Error "$Path is not a file..."
13 | return
14 | }
15 |
16 | $sourceItem = Get-Item $Path
17 | $targetName = $sourceItem.Name + '.gz'
18 |
19 | try{
20 | $sourceStream = $sourceItem.OpenRead()
21 | $targetStream = New-Object IO.FileStream $targetName ,'Create','Write','Read'
22 | $gzipStream = [System.IO.Compression.GZipStream]::new($targetStream, [System.IO.Compression.CompressionMode]::Compress)
23 | $sourceStream.CopyTo($gzipStream)
24 | }
25 | catch{
26 | throw
27 | }
28 | finally{
29 | $gzipStream,$targetStream,$sourceStream |ForEach-Object {
30 | if($_){
31 | $_.Dispose()
32 | }
33 | }
34 | }
35 |
36 | return Get-Item $targetName
37 | }
38 |
39 | function ProcessTemplate
40 | {
41 | param(
42 | [Parameter(Mandatory)]
43 | [string]$File = 'file.js',
44 |
45 | [switch]$PassThru
46 | )
47 | Write-Host "Processing " $File
48 | $js = Get-Item $File -ErrorAction SilentlyContinue
49 | if(-not $?){
50 | Write-Error "$File not found"
51 | return
52 | }
53 |
54 | $gz = Get-Item "${File}.gz" -ErrorAction SilentlyContinue
55 |
56 | if(-not $? -or $js.LastWriteTime -ge $gz.LastWriteTime){
57 | Write-Host "Creating " $File ".gz"
58 | $gz = New-Gzip -Path $js.FullName
59 | }
60 |
61 | if($PassThru){
62 | return $gz
63 | }
64 | }
65 |
66 | ProcessTemplate -File responsivetemplate.html
67 | ProcessTemplate -File ReportBase.css
68 | ProcessTemplate -File ReportBase.js
69 | ProcessTemplate -File ReportMain.js
70 |
--------------------------------------------------------------------------------
/Rules/ADConnectVersion.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.Data;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 |
14 | namespace PingCastleCloud.Rules
15 | {
16 | [RuleModel("ADConnectVersion")]
17 | [RuleComputation(RuleComputationType.TriggerOnPresence, 15)]
18 | [RuleMaturityLevel(1)]
19 | [RuleMitreAttackTechnique(MitreAttackTechnique.ManintheMiddle)]
20 | public class ADConnectVersion : RuleBase
21 | {
22 | protected override int? AnalyzeDataNew(HealthCheckCloudData healthCheckCloudData)
23 | {
24 | if (healthCheckCloudData.ProvisionDirectorySynchronizationStatus == "Enabled")
25 | {
26 | Version v;
27 | if (Version.TryParse(healthCheckCloudData.ProvisionDirSyncClientVersion, out v))
28 | {
29 | if (v.Major == 1)
30 | {
31 | if (v < new Version(1, 6, 11, 3))
32 | {
33 | AddRawDetail(healthCheckCloudData.ProvisionDirSyncClientVersion);
34 | }
35 | }
36 | else if (v.Major == 2)
37 | {
38 | if (v < new Version(2, 0, 8, 0))
39 | {
40 | AddRawDetail(healthCheckCloudData.ProvisionDirSyncClientVersion);
41 | }
42 | }
43 | }
44 | }
45 | return null;
46 | }
47 |
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/Properties/AssemblyInfo.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using System.Reflection;
8 | using System.Runtime.CompilerServices;
9 | using System.Runtime.InteropServices;
10 |
11 | // Les informations générales relatives à un assembly dépendent de
12 | // l'ensemble d'attributs suivant. Changez les valeurs de ces attributs pour modifier les informations
13 | // associées à un assembly.
14 | [assembly: AssemblyTitle("PingCastleCloud")]
15 | [assembly: AssemblyDescription("")]
16 | [assembly: AssemblyConfiguration("")]
17 | [assembly: AssemblyCompany("")]
18 | [assembly: AssemblyProduct("PingCastleCloud")]
19 | [assembly: AssemblyCopyright("Copyright © 2022")]
20 | [assembly: AssemblyTrademark("")]
21 | [assembly: AssemblyCulture("")]
22 |
23 | // L'affectation de la valeur false à ComVisible rend les types invisibles dans cet assembly
24 | // aux composants COM. Si vous devez accéder à un type dans cet assembly à partir de
25 | // COM, affectez la valeur true à l'attribut ComVisible sur ce type.
26 | [assembly: ComVisible(false)]
27 |
28 | // Le GUID suivant est pour l'ID de la typelib si ce projet est exposé à COM
29 | [assembly: Guid("123099d2-462c-4712-af04-d9455461e1ba")]
30 |
31 | // Les informations de version pour un assembly se composent des quatre valeurs suivantes :
32 | //
33 | // Version principale
34 | // Version secondaire
35 | // Numéro de build
36 | // Révision
37 | //
38 | // Vous pouvez spécifier toutes les valeurs ou indiquer les numéros de build et de révision par défaut
39 | // en utilisant '*', comme indiqué ci-dessous :
40 | // [assembly: AssemblyVersion("1.0.*")]
41 | [assembly: AssemblyVersion("1.0.0.0")]
42 | [assembly: AssemblyFileVersion("1.0.0.0")]
43 |
--------------------------------------------------------------------------------
/RESTServices/Azure/AzureADConnectApi.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using Newtonsoft.Json;
8 | using PingCastleCloud.Credentials;
9 | using PingCastleCloud.Tokens;
10 | using System;
11 | using System.Collections.Generic;
12 | using System.Collections.Specialized;
13 | using System.Linq;
14 | using System.Net.Http;
15 | using System.Text;
16 | using System.Threading.Tasks;
17 | using System.Web;
18 |
19 | namespace PingCastleCloud.RESTServices.Azure
20 | {
21 | [AzureService("d3590ed6-52b3-4102-aeff-aad2292ab01c", "74658136-14ec-4630-ad9b-26e160ff0fc6")]
22 | public class AzureADConnectApi : RESTClientBase, IAzureService
23 | {
24 | public AzureADConnectApi(IAzureCredential credential) : base(credential)
25 | {
26 | }
27 |
28 | protected override string BuidEndPoint(string function, string optionalQuery)
29 | {
30 | var query = HttpUtility.ParseQueryString(optionalQuery);
31 | query["api-version"] = "2.0";
32 |
33 | var builder = new UriBuilder("https://main.iam.ad.ext.azure.com/api/Directories/" + function);
34 | builder.Query = query.ToString();
35 | return builder.ToString();
36 | }
37 |
38 | public ADConnectStatusResponse ADConnectStatus()
39 | {
40 | return CallEndPoint("ADConnectStatus");
41 | }
42 |
43 | public class ADConnectStatusResponse
44 | {
45 | public int verifiedDomainCount { get; set; }
46 | public int verifiedCustomDomainCount { get; set; }
47 | public int federatedDomainCount { get; set; }
48 | public int? numberOfHoursFromLastSync { get; set; }
49 | public bool? dirSyncEnabled { get; set; }
50 | public bool? dirSyncConfigured { get; set; }
51 | public bool? passThroughAuthenticationEnabled { get; set; }
52 | public bool? seamlessSingleSignOnEnabled { get; set; }
53 | }
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/CreateSecureAppCert.ps1:
--------------------------------------------------------------------------------
1 | #=======================================================================================
2 | #region PARAMETERS
3 | #=======================================================================================
4 | Param(
5 | [string]$TenantName,
6 | [string]$ExportPrivateKey,
7 | [string]$ExportPath
8 | )
9 | #endregion
10 | #=======================================================================================
11 |
12 | $DateTime = (Get-Date -Format "yyyyMMdd-HHmmss").tostring()
13 | $ShortTenantName = ($TenantName -split "\.")[0]
14 |
15 | # Where to export the certificate without the private key
16 | $CerOutputPath = "$ExportPath\$DateTime-$ShortTenantName-AppCert"
17 |
18 | # Expiration date of the new certificate
19 | $ExpirationDate = (Get-Date).AddYears(2)
20 |
21 | # Splat for readability
22 | $CreateCertificateSplat = @{
23 | FriendlyName = "PSCC-$TenantName-App"
24 | DnsName = $TenantName
25 | CertStoreLocation = "Cert:\CurrentUser\My"
26 | NotAfter = $ExpirationDate
27 | KeyExportPolicy = "Exportable"
28 | KeySpec = "Signature"
29 | Provider = "Microsoft Enhanced RSA and AES Cryptographic Provider"
30 | HashAlgorithm = "SHA256"
31 | }
32 |
33 | # Create certificate
34 | $Certificate = New-SelfSignedCertificate @CreateCertificateSplat
35 |
36 | # Get certificate path
37 | $CertificatePath = Join-Path -Path "Cert:\CurrentUser\My" -ChildPath $Certificate.Thumbprint
38 |
39 | # Export certificate without private key
40 | Export-Certificate -Cert $CertificatePath -FilePath "$CerOutputPath.cer" | Out-Null
41 | if($ExportPrivateKey -eq $true)
42 | {
43 | Write-Host "Please create a password for the certificate which will be exported with the private key: " -ForegroundColor Yellow -NoNewline
44 | $Password = Read-Host -AsSecureString
45 | # Export certificate with private key
46 | Export-PfxCertificate -Cert $CertificatePath -FilePath "$CerOutputPath.pfx" -Password $Password | Out-Null
47 | }
48 |
49 | Write-Host "Certificate validity : $($Certificate.NotBefore) through $($Certificate.NotAfter) "
50 | Write-Host "Certificate thumbprint : $($Certificate.Thumbprint)"
51 | Write-Host "Certificate exported to : $CerOutputPath"
52 |
53 |
--------------------------------------------------------------------------------
/Tokens/JwtToken.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.Common;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.IO;
11 | using System.Linq;
12 | using System.Runtime.Serialization;
13 | using System.Runtime.Serialization.Json;
14 | using System.Text;
15 | using System.Threading.Tasks;
16 |
17 | namespace PingCastleCloud.Tokens
18 | {
19 | public class JwtToken : JsonSerialization
20 | {
21 |
22 | public string request_nonce { get; set; }
23 |
24 | public string refresh_token { get; set; }
25 |
26 | public string aud { get; set; }
27 |
28 | public string iss { get; set; }
29 |
30 | public long iat { get; set; }
31 |
32 | public long nbf { get; set; }
33 |
34 | public long exp { get; set; }
35 |
36 | public string act { get; set; }
37 |
38 | public string aio { get; set; }
39 |
40 | public List amr { get; set; }
41 |
42 | public string appid { get; set; }
43 |
44 | public string appidacr { get; set; }
45 |
46 | public string deviceid { get; set; }
47 |
48 | public string family_name { get; set; }
49 |
50 | public string given_name { get; set; }
51 |
52 | public string ipaddr { get; set; }
53 |
54 | public string name { get; set; }
55 |
56 | public string oid { get; set; }
57 |
58 | public string onprem_sid { get; set; }
59 |
60 | public string puid { get; set; }
61 |
62 | public string rh { get; set; }
63 |
64 | public string scp { get; set; }
65 |
66 | public string sub { get; set; }
67 |
68 | public string tenant_region_scope { get; set; }
69 |
70 | public string tid { get; set; }
71 |
72 | public string unique_name { get; set; }
73 |
74 | public string upn { get; set; }
75 |
76 | public string uti { get; set; }
77 |
78 | public string ver { get; set; }
79 |
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/Credentials/CredentialBase.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.RESTServices.Azure;
8 | using PingCastleCloud.Tokens;
9 | using System;
10 | using System.Collections.Generic;
11 | using System.Linq;
12 | using System.Text;
13 | using System.Threading.Tasks;
14 |
15 | namespace PingCastleCloud.Credentials
16 | {
17 | public abstract class CredentialBase : IAzureCredential
18 | {
19 | public CredentialBase() : this(null)
20 | {
21 |
22 | }
23 | public CredentialBase(string tenantid)
24 | {
25 | this.tenantId = tenantid;
26 | }
27 |
28 | Dictionary cache = new Dictionary();
29 | public Token LastTokenQueried { get; protected set; }
30 | public async Task GetToken() where T : IAzureService
31 | {
32 | Token token;
33 | if (cache.ContainsKey(typeof(T)))
34 | {
35 | token = cache[typeof(T)];
36 |
37 | // TODO refresh
38 |
39 | return token;
40 | }
41 | token = await TokenFactory.GetToken(this);
42 | LastTokenQueried = token;
43 | cache[typeof(T)] = token;
44 | return token;
45 | }
46 | string tenantId;
47 | public string Tenantid
48 | {
49 | get
50 | {
51 | if (string.IsNullOrEmpty(tenantId) && cache.Count > 0)
52 | {
53 | var token = cache.Values.FirstOrDefault();
54 | tenantId = token.ToJwtToken().tid;
55 | }
56 | return tenantId;
57 | }
58 | }
59 |
60 | string tenantidToQuery;
61 | public string TenantidToQuery
62 | {
63 | get
64 | {
65 | return tenantidToQuery;
66 | }
67 | set
68 | {
69 | if (tenantidToQuery == value)
70 | return;
71 | if (string.IsNullOrEmpty(value))
72 | return;
73 | tenantidToQuery = value;
74 | cache.Clear();
75 | }
76 | }
77 | }
78 | }
79 |
--------------------------------------------------------------------------------
/PublicServices/UserRealmCT.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.Common;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Runtime.Serialization;
12 | using System.Text;
13 | using System.Threading.Tasks;
14 |
15 | namespace PingCastleCloud.PublicServices
16 | {
17 | [DataContractAttribute]
18 | public class UserRealmCT : JsonSerialization
19 | {
20 | [DataMember]
21 | public string Username { get; set; }
22 | [DataMember]
23 | public string Display { get; set; }
24 | [DataMember]
25 | public int IfExistsResult { get; set; }
26 | [DataMember]
27 | public bool IsUnmanaged { get; set; }
28 | [DataMember]
29 | public int ThrottleStatus { get; set; }
30 | [DataMember]
31 | public UserRealmCTCredentials Credentials { get; set; }
32 | [DataMember]
33 | public UserRealmCTEstsProperties EstsProperties { get; set; }
34 | [DataMember]
35 | public string FlowToken { get; set; }
36 | [DataMember]
37 | public bool IsSignupDisallowed { get; set; }
38 | [DataMember]
39 | public string apiCanary { get; set; }
40 | }
41 |
42 | public class UserRealmCTCredentials
43 | {
44 | [DataMember]
45 | public int PrefCredential { get; set; }
46 | [DataMember]
47 | public bool HasPassword { get; set; }
48 | [DataMember]
49 | public string RemoteNgcParams { get; set; }
50 | [DataMember]
51 | public string FidoParams { get; set; }
52 | [DataMember]
53 | public string SasParams { get; set; }
54 | [DataMember]
55 | public string CertAuthParams { get; set; }
56 | [DataMember]
57 | public string GoogleParams { get; set; }
58 | [DataMember]
59 | public string FacebookParams { get; set; }
60 | [DataMember]
61 | public string FederationRedirectUrl { get; set; }
62 | }
63 |
64 | public class UserRealmCTEstsProperties
65 | {
66 | [DataMember]
67 | public List UserTenantBranding { get; set; }
68 | [DataMember]
69 | public int DomainType { get; set; }
70 |
71 | }
72 | }
73 |
--------------------------------------------------------------------------------
/Tokens/CookieManager.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using System.Runtime.InteropServices;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 |
14 | namespace PingCastleCloud.RESTServices
15 | {
16 | [StructLayout(LayoutKind.Sequential)]
17 | public struct ProofOfPossessionCookieInfo
18 | {
19 | [MarshalAs(UnmanagedType.LPWStr)]
20 | public string Name;
21 | [MarshalAs(UnmanagedType.LPWStr)]
22 | public string Data;
23 | public readonly uint Flags;
24 | [MarshalAs(UnmanagedType.LPWStr)]
25 | public string P3PHeader;
26 | }
27 |
28 |
29 | // All these are defined in the Win10 WDK
30 | [Guid("CDAECE56-4EDF-43DF-B113-88E4556FA1BB")]
31 | [ComImport]
32 | [InterfaceType(ComInterfaceType.InterfaceIsIUnknown)]
33 | internal interface IProofOfPossessionCookieInfoManager
34 | {
35 | int GetCookieInfoForUri(
36 | [MarshalAs(UnmanagedType.LPWStr)] string Uri,
37 | out uint cookieInfoCount,
38 | out IntPtr cookieInfo
39 | );
40 | }
41 |
42 | [Guid("A9927F85-A304-4390-8B23-A75F1C668600")]
43 | [ComImport]
44 | public class WindowsTokenProvider
45 | {
46 | }
47 |
48 |
49 | public class CookieInfoManager
50 | {
51 | public static List GetCookieInforForUri(string uri)
52 | {
53 | var output = new List();
54 | var provider = (IProofOfPossessionCookieInfoManager)new WindowsTokenProvider();
55 | IntPtr ptr;
56 | uint count;
57 | var error = provider.GetCookieInfoForUri(uri, out count, out ptr);
58 | if (error != 0)
59 | throw new COMException("unable to call GetCookieInfoForUri", error);
60 | var offset = ptr;
61 | for (int i = 0; i < count; i++)
62 | {
63 | var info = (ProofOfPossessionCookieInfo)Marshal.PtrToStructure(offset, typeof(ProofOfPossessionCookieInfo));
64 | output.Add(info);
65 | }
66 |
67 | Marshal.FreeCoTaskMem(ptr);
68 | return output;
69 | }
70 | }
71 |
72 | }
73 |
--------------------------------------------------------------------------------
/PublicServices/OpenIDConfiguration.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.Common;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.Linq;
11 | using System.Runtime.Serialization;
12 | using System.Text;
13 | using System.Threading.Tasks;
14 |
15 | namespace PingCastleCloud.PublicServices
16 | {
17 | [DataContractAttribute]
18 | public class OpenIDConfiguration : JsonSerialization
19 | {
20 | [DataMember]
21 | public string token_endpoint { get; set; }
22 | [DataMember]
23 | public string[] token_endpoint_auth_methods_supported { get; set; }
24 | [DataMember]
25 | public string[] response_modes_supported { get; set; }
26 | [DataMember]
27 | public string[] subject_types_supported { get; set; }
28 | [DataMember]
29 | public string[] id_token_signing_alg_values_supported { get; set; }
30 | [DataMember]
31 | public string[] response_types_supported { get; set; }
32 | [DataMember]
33 | public string[] scopes_supported { get; set; }
34 | [DataMember]
35 | public string issuer { get; set; }
36 | [DataMember]
37 | public bool microsoft_multi_refresh_token { get; set; }
38 | [DataMember]
39 | public string authorization_endpoint { get; set; }
40 | [DataMember]
41 | public string device_authorization_endpoint { get; set; }
42 | [DataMember]
43 | public bool http_logout_supported { get; set; }
44 | [DataMember]
45 | public bool frontchannel_logout_supported { get; set; }
46 | [DataMember]
47 | public string end_session_endpoint { get; set; }
48 | [DataMember]
49 | public string[] claims_supported { get; set; }
50 | [DataMember]
51 | public string check_session_iframe { get; set; }
52 | [DataMember]
53 | public string userinfo_endpoint { get; set; }
54 | [DataMember]
55 | public string kerberos_endpoint { get; set; }
56 | [DataMember]
57 | public string tenant_region_scope { get; set; }
58 | [DataMember]
59 | public string cloud_instance_name { get; set; }
60 | [DataMember]
61 | public string cloud_graph_host_name { get; set; }
62 | [DataMember]
63 | public string msgraph_host { get; set; }
64 | [DataMember]
65 | public string rbac_url { get; set; }
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Ping Castle Cloud
2 |
3 | important: the source code has been moved to the main PingCastle project.
4 | this project is now archived.
5 |
6 |
7 | ## Introduction
8 |
9 | Ping Castle Cloud is a tool designed to assess quickly the AzureAD security level with a methodology based on risk assessment and a maturity framework.
10 | It does not aim at a perfect evaluation but rather as an efficiency compromise.
11 | It is inspired from the [Ping Castle project](https://pingcastle.com/)
12 |
13 | ```
14 | \==--O___ PingCastle Cloud (Version 1.0.0.0 17/07/2022 18:58:40)
15 | \ / \ ¨¨> Get Active Directory Security at 80% in 20% of the time
16 | \/ \ ,' End of support: 31/07/2023
17 | O¨---O
18 | \ ,' Vincent LE TOUX (contact@pingcastle.com)
19 | v twitter: @mysmartlogon https://www.pingcastle.com
20 | What do you want to do?
21 | =======================
22 | Using interactive mode.
23 | Do not forget that there are other command line switches like --help that you can use
24 | 1-healthcheck -Score the risk of a domain
25 | 2-exportasguest-Export users and group as a Guest
26 | 3-advanced -Open the advanced menu
27 | 0-Exit
28 |
29 | ```
30 |
31 | Check https://www.pingcastle.com for the documentation and methodology
32 |
33 | ## Build
34 |
35 | PingCastle is a c# project which can be build from Visual Studio 2019
36 |
37 | ## Support & lifecycle
38 |
39 | For support requests, you should contact support@pingcastle.com
40 | The support for the basic edition is made on a best effort basis and fixes delivered when a new version is delivered.
41 |
42 | The Basic Edition of PingCastleCloud is released every 6 months (January, August) and this repository is updated at each release.
43 |
44 | If you need changes, please contact contact@pingcastle.com for support packages.
45 |
46 | ## License
47 |
48 | PingCastleCloud source code is licensed under a proprietary license and the Non-Profit Open Software License ("Non-Profit OSL") 3.0.
49 |
50 | Except if a license is purchased, you are not allowed to make any profit from this source code.
51 | To be more specific:
52 | * It is allowed to run PingCastle without purchasing any license on for profit companies if the company itself (or its ITSM provider) run it.
53 | * To build services based on PingCastle AND earning money from that, you MUST purchase a license.
54 |
55 | Ping Castle uses the following Open source components:
56 |
57 | * [Bootstrap](https://getbootstrap.com/) licensed under the [MIT license](https://tldrlegal.com/license/mit-license)
58 | * [JQuery](https://jquery.org) licensed under the [MIT license](https://tldrlegal.com/license/mit-license)
59 | * [vis.js](http://visjs.org/) licensed under the [MIT license](https://tldrlegal.com/license/mit-license)
60 |
61 | ## Author
62 |
63 | Author: Vincent LE TOUX
64 |
65 | You can contact me at vincent.letoux@gmail.com
66 |
67 |
68 |
69 |
70 |
--------------------------------------------------------------------------------
/UI/AuthenticationDialog.Designer.cs:
--------------------------------------------------------------------------------
1 | namespace PingCastleCloud.UI
2 | {
3 | partial class AuthenticationDialog
4 | {
5 | ///
6 | /// Required designer variable.
7 | ///
8 | private System.ComponentModel.IContainer components = null;
9 |
10 | ///
11 | /// Clean up any resources being used.
12 | ///
13 | /// true if managed resources should be disposed; otherwise, false.
14 | protected override void Dispose(bool disposing)
15 | {
16 | if (disposing && (components != null))
17 | {
18 | components.Dispose();
19 | }
20 | base.Dispose(disposing);
21 | }
22 |
23 | #region Windows Form Designer generated code
24 |
25 | ///
26 | /// Required method for Designer support - do not modify
27 | /// the contents of this method with the code editor.
28 | ///
29 | private void InitializeComponent()
30 | {
31 | this.components = new System.ComponentModel.Container();
32 | System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(AuthenticationDialog));
33 | this.webBrowser = new System.Windows.Forms.WebBrowser();
34 | this.timerForAutoSignAttempt = new System.Windows.Forms.Timer(this.components);
35 | this.SuspendLayout();
36 | //
37 | // webBrowser
38 | //
39 | this.webBrowser.Dock = System.Windows.Forms.DockStyle.Fill;
40 | this.webBrowser.Location = new System.Drawing.Point(0, 0);
41 | this.webBrowser.MinimumSize = new System.Drawing.Size(20, 20);
42 | this.webBrowser.Name = "webBrowser";
43 | this.webBrowser.Size = new System.Drawing.Size(543, 887);
44 | this.webBrowser.TabIndex = 0;
45 | this.webBrowser.Url = new System.Uri("http://w", System.UriKind.Absolute);
46 | //
47 | // timerForAutoSignAttempt
48 | //
49 | this.timerForAutoSignAttempt.Tick += new System.EventHandler(this.timerForAutoSignAttempt_Tick);
50 | //
51 | // AuthenticationDialog
52 | //
53 | this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
54 | this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
55 | this.ClientSize = new System.Drawing.Size(543, 887);
56 | this.Controls.Add(this.webBrowser);
57 | this.Icon = ((System.Drawing.Icon)(resources.GetObject("$this.Icon")));
58 | this.Name = "AuthenticationDialog";
59 | this.Text = "PingCastle Cloud";
60 | this.ResumeLayout(false);
61 |
62 | }
63 |
64 | #endregion
65 |
66 | private System.Windows.Forms.WebBrowser webBrowser;
67 | private System.Windows.Forms.Timer timerForAutoSignAttempt;
68 | }
69 | }
--------------------------------------------------------------------------------
/PublicServices/PublicService.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.Common;
8 | using PingCastleCloud.RESTServices;
9 | using PingCastleCloud.RESTServices.Azure;
10 | using System;
11 | using System.Collections.Generic;
12 | using System.Linq;
13 | using System.Net.Http;
14 | using System.Text;
15 | using System.Threading.Tasks;
16 |
17 | namespace PingCastleCloud.PublicServices
18 | {
19 | public class PublicService
20 | {
21 | public static async Task GetUserRealmv1(string domain)
22 | {
23 | var httpClient = HttpClientHelper.GetHttpClient();
24 |
25 | var response = await httpClient.GetStringAsync(Constants.UserRealmEndpoint + domain + "?api-version=1.0");
26 |
27 | return UserRealmV1.LoadFromString(response);
28 | }
29 |
30 | public static async Task GetUserRealmV2(string domain)
31 | {
32 | var httpClient = HttpClientHelper.GetHttpClient();
33 |
34 | var response = await httpClient.GetStringAsync(Constants.UserRealmEndpoint + domain + "?api-version=2.0");
35 |
36 | return UserRealmV2.LoadFromString(response);
37 | }
38 |
39 | public static async Task GetUserRealmSRF(string domain)
40 | {
41 | var httpClient = HttpClientHelper.GetHttpClient();
42 |
43 | var response = await httpClient.GetStringAsync(Constants.UserRealmSRFEndpoint + domain);
44 |
45 | return UserRealmSRF.LoadFromString(response);
46 | }
47 |
48 | public static async Task GetUserRealmCT(string email)
49 | {
50 | var httpClient = HttpClientHelper.GetHttpClient();
51 |
52 | var request = new UserRealmCTRequest
53 | {
54 | username = email,
55 | isOtherIdpSupported = true,
56 | checkPhones = true,
57 | isRemoteNGCSupported = false,
58 | isCookieBannerShown = false,
59 | isFidoSupported = false,
60 | originalRequest = "",
61 | flowToken = ""
62 | };
63 |
64 | var stringContent = new StringContent(request.ToJsonString());
65 | var response = await httpClient.PostAsync(Constants.UserRealmCTEndpoint, stringContent);
66 | var t = await response.Content.ReadAsStringAsync();
67 | return UserRealmCT.LoadFromString(t);
68 | }
69 |
70 | public static async Task GetOpenIDConfiguration(string domain)
71 | {
72 | var httpClient = HttpClientHelper.GetHttpClient();
73 |
74 | var response = await httpClient.GetStringAsync(Constants.OpenIdConfigurationEndpoint.Replace("xxxxx", domain));
75 |
76 | return OpenIDConfiguration.LoadFromString(response);
77 | }
78 |
79 | }
80 | }
81 |
--------------------------------------------------------------------------------
/Common/JsonSerialization.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using Newtonsoft.Json;
8 | using System;
9 | using System.Collections.Generic;
10 | using System.IO;
11 | using System.Linq;
12 | using System.Text;
13 | using System.Threading.Tasks;
14 |
15 | namespace PingCastleCloud.Common
16 | {
17 | public abstract class JsonSerialization
18 | {
19 | public static T LoadFromString(string input)
20 | {
21 | /*using (var stream = new MemoryStream())
22 | {
23 | var bytes = Encoding.UTF8.GetBytes(input);
24 | stream.Write(bytes, 0, bytes.Length);
25 | stream.Position = 0;
26 | return LoadFromStream(stream);
27 | }*/
28 |
29 | return JsonConvert.DeserializeObject(input);
30 | }
31 | public static T LoadFromStream(Stream input)
32 | {
33 | /*T t;
34 | var serializer = new DataContractJsonSerializer(typeof(T));
35 |
36 | t = (T)serializer.ReadObject(input);
37 | */
38 | using (StreamReader sr = new StreamReader(input))
39 | using (JsonReader reader = new JsonTextReader(sr))
40 | {
41 | JsonSerializer serializer = new JsonSerializer();
42 | return (T) serializer.Deserialize(reader, typeof(T));
43 | }
44 | }
45 |
46 | public string ToJsonString()
47 | {
48 | return JsonConvert.SerializeObject(this);
49 | /*
50 | var serializer = new DataContractJsonSerializer(typeof(T));
51 | using (var ms = new MemoryStream())
52 | {
53 | serializer.WriteObject(ms, this);
54 | var buf = ms.ToArray();
55 | return Encoding.UTF8.GetString(buf);
56 | }*/
57 | }
58 |
59 | public string ToBase64JsonString()
60 | {
61 | var data = JsonConvert.SerializeObject(this);
62 | var payloadString = Encoding.UTF8.GetBytes(data);
63 | return Convert.ToBase64String(payloadString);
64 | }
65 |
66 | public static T LoadFromBase64String(string payload)
67 | {
68 | var payloadBytes = Convert.FromBase64String(payload.PadRight(payload.Length + (payload.Length * 3) % 4, '='));
69 | var payloadString = Encoding.UTF8.GetString(payloadBytes);
70 | return JsonConvert.DeserializeObject(payloadString);
71 | /*T t;
72 | var serializer = new DataContractJsonSerializer(typeof(T));
73 | using (var stream = new MemoryStream())
74 | {
75 | stream.Write(payloadString, 0, payloadString.Length);
76 | stream.Position = 0;
77 | t = (T)serializer.ReadObject(stream);
78 | }
79 |
80 | return t;*/
81 | }
82 | }
83 | }
84 |
--------------------------------------------------------------------------------
/PublicServices/TenantBrandingInfo.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using System.Runtime.Serialization;
11 | using System.Text;
12 | using System.Threading.Tasks;
13 |
14 | namespace PingCastleCloud.PublicServices
15 | {
16 | [DataContractAttribute]
17 | public class TenantBrandingInfo
18 | {
19 | [DataMember]
20 | public int Locale { get; set; }
21 | [DataMember]
22 | public string BannerLogo { get; set; }
23 | [DataMember]
24 | public string TileLogo { get; set; }
25 | [DataMember]
26 | public string TileDarkLogo { get; set; }
27 | [DataMember]
28 | public string Illustration { get; set; }
29 | [DataMember]
30 | public string BackgroundColor { get; set; }
31 | [DataMember]
32 | public string BoilerPlateText { get; set; }
33 | [DataMember]
34 | public string UserIdLabel { get; set; }
35 | [DataMember]
36 | public bool KeepMeSignedInDisabled { get; set; }
37 | [DataMember]
38 | public bool UseTransparentLightBox { get; set; }
39 | [DataMember]
40 | public TenantBrandingInfoLayoutTemplateConfig LayoutTemplateConfig { get; set; }
41 | [DataMember]
42 | public TenantBrandingInfoCustomizationFiles CustomizationFiles { get; set; }
43 |
44 | }
45 |
46 | [DataContractAttribute]
47 | public class TenantBrandingInfoLayoutTemplateConfig
48 | {
49 | [DataMember]
50 | public bool showHeader { get; set; }
51 | [DataMember]
52 | public string headerLogo { get; set; }
53 | [DataMember]
54 | public int layoutType { get; set; }
55 | [DataMember]
56 | public bool hideCantAccessYourAccount { get; set; }
57 | [DataMember]
58 | public bool hideForgotMyPassword { get; set; }
59 | [DataMember]
60 | public bool hideResetItNow { get; set; }
61 | [DataMember]
62 | public bool hideAccountResetCredentials { get; set; }
63 | [DataMember]
64 | public bool showFooter { get; set; }
65 | [DataMember]
66 | public bool hideTOU { get; set; }
67 | [DataMember]
68 | public bool hidePrivacy { get; set; }
69 |
70 | }
71 |
72 | [DataContractAttribute]
73 | public class TenantBrandingInfoCustomizationFiles
74 | {
75 | [DataMember]
76 | public TenantBrandingInfoCustomizationFilesStrings strings { get; set; }
77 | [DataMember]
78 | public string customCssUrl { get; set; }
79 |
80 | }
81 |
82 | [DataContractAttribute]
83 | public class TenantBrandingInfoCustomizationFilesStrings
84 | {
85 | [DataMember]
86 | public string adminConsent { get; set; }
87 | [DataMember]
88 | public string attributeCollection { get; set; }
89 | [DataMember]
90 | public string authenticatorNudgeScreen { get; set; }
91 | [DataMember]
92 | public string conditionalAccess { get; set; }
93 |
94 | }
95 | }
96 |
--------------------------------------------------------------------------------
/RESTServices/Azure/MicrosoftGraph.cs:
--------------------------------------------------------------------------------
1 | //
2 | // Copyright (c) Vincent LE TOUX for Ping Castle. All rights reserved.
3 | // https://www.pingcastle.com
4 | //
5 | // Licensed under the Non-Profit OSL. See LICENSE file in the project root for full license information.
6 | //
7 | using PingCastleCloud.Credentials;
8 | using PingCastleCloud.RESTServices.Azure;
9 | using PingCastleCloud.Tokens;
10 | using System;
11 | using System.Collections.Generic;
12 | using System.Linq;
13 | using System.Text;
14 | using System.Threading.Tasks;
15 | using System.Web;
16 |
17 | namespace PingCastleCloud.RESTServices
18 | {
19 | [AzureService("1b730954-1685-4b74-9bfd-dac224a7b894", "https://graph.microsoft.com")]
20 | public class MicrosoftGraph : RESTClientBase, IAzureService
21 | {
22 | public MicrosoftGraph(IAzureCredential credential) : base(credential)
23 | {
24 | }
25 | protected override string BuidEndPoint(string function, string optionalQuery)
26 | {
27 | var query = HttpUtility.ParseQueryString(optionalQuery);
28 | //query["api-version"] = "1.61-internal";
29 |
30 | var builder = new UriBuilder("https://graph.microsoft.com/beta/" + function);
31 | builder.Query = query.ToString();
32 | return builder.ToString();
33 | }
34 |
35 | public GraphAPI.User GetMe()
36 | {
37 | return CallEndPoint("me");
38 | }
39 |
40 | public List GetAuthorizationPolicy()
41 | {
42 | return CallEndPointWithPaggingAsync