private void StartConsentFlow(string loginEndPoint, AzureADApp azureApp, string redirectUri, string token, HttpClient httpClient, PSObject record, CmdletMessageWriter messageWriter, List <PermissionScope> scopes) { Host.UI.WriteLine(ConsoleColor.Yellow, Host.UI.RawUI.BackgroundColor, $"Starting consent flow."); var resource = scopes.FirstOrDefault(s => s.resourceAppId == PermissionScopes.ResourceAppId_Graph) != null ? $"https://{AzureAuthHelper.GetGraphEndPoint(AzureEnvironment)}/.default" : "https://microsoft.sharepoint-df.com/.default"; var consentUrl = $"{loginEndPoint}/{Tenant}/v2.0/adminconsent?client_id={azureApp.AppId}&scope={resource}&redirect_uri={redirectUri}"; if (OperatingSystem.IsWindows() && !NoPopup) { var waitTime = 60; // CmdletMessageWriter.WriteFormattedWarning(this, $"Waiting {waitTime} seconds to launch the consent flow in a popup window.\n\nThis wait is required to make sure that Azure AD is able to initialize all required artifacts. You can always navigate to the consent page manually:\n\n{consentUrl}"); var progressRecord = new ProgressRecord(1, "Please wait...", $"Waiting {waitTime} seconds to launch the consent flow in a popup window. This wait is required to make sure that Azure AD is able to initialize all required artifacts."); for (var i = 0; i < waitTime; i++) { progressRecord.PercentComplete = Convert.ToInt32((Convert.ToDouble(i) / Convert.ToDouble(waitTime)) * 100); WriteProgress(progressRecord); // if (Convert.ToDouble(i) % Convert.ToDouble(10) > 0) // { // Host.UI.Write(ConsoleColor.Yellow, Host.UI.RawUI.BackgroundColor, "-"); // } // else // { // Host.UI.Write(ConsoleColor.Yellow, Host.UI.RawUI.BackgroundColor, $"[{i}]"); // } System.Threading.Thread.Sleep(1000); // Check if CTRL+C has been pressed and if so, abort the wait if (Stopping) { Host.UI.WriteLine("Wait cancelled. You can provide consent manually by navigating to"); Host.UI.WriteLine(consentUrl); break; } } progressRecord.RecordType = ProgressRecordType.Completed; WriteProgress(progressRecord); if (!Stopping) { // Host.UI.WriteLine(ConsoleColor.Yellow, Host.UI.RawUI.BackgroundColor, $"[{waitTime}]"); // Host.UI.WriteLine(); if (ParameterSpecified(nameof(Interactive))) { using (var authManager = AuthenticationManager.CreateWithInteractiveLogin(azureApp.AppId, (url, port) => { BrowserHelper.OpenBrowserForInteractiveLogin(url, port, true, cancellationTokenSource); }, Tenant, "You successfully provided consent", "You failed to provide consent.", AzureEnvironment)) { authManager.GetAccessToken(resource, Microsoft.Identity.Client.Prompt.Consent); } } else { BrowserHelper.GetWebBrowserPopup(consentUrl, "Please provide consent", new[] { ("https://pnp.github.io/powershell/consent.html", BrowserHelper.UrlMatchType.StartsWith) }, cancellationTokenSource: cancellationTokenSource, cancelOnClose: false);
private void StartConsentFlow(string loginEndPoint, AzureApp azureApp, string redirectUri, string token, HttpClient httpClient, PSObject record) { var consentUrl = $"{loginEndPoint}/{Tenant}/v2.0/adminconsent?client_id={azureApp.AppId}&scope=https://microsoft.sharepoint-df.com/.default&redirect_uri={redirectUri}"; if (OperatingSystem.IsWindows() && !NoPopup) { var waitTime = 60; CmdletMessageWriter.WriteFormattedWarning(this, $"Waiting {waitTime} seconds to launch consent flow in a popup window.\n\nThis wait is required to make sure that Azure AD is able to initialize all required artifacts. You can always navigate to the consent page manually:\n\n{consentUrl}"); for (var i = 0; i < waitTime; i++) { if (Convert.ToDouble(i) % Convert.ToDouble(10) > 0) { Host.UI.Write(ConsoleColor.Yellow, Host.UI.RawUI.BackgroundColor, "-"); } else { Host.UI.Write(ConsoleColor.Yellow, Host.UI.RawUI.BackgroundColor, $"[{i}]"); } System.Threading.Thread.Sleep(1000); // Check if CTRL+C has been pressed and if so, abort the wait if (Stopping) { break; } } if (!Stopping) { Host.UI.WriteLine(ConsoleColor.Yellow, Host.UI.RawUI.BackgroundColor, $"[{waitTime}]"); Host.UI.WriteLine(); BrowserHelper.GetWebBrowserPopup(consentUrl, "Please provide consent", new[] { (redirectUri, BrowserHelper.UrlMatchType.StartsWith) });
protected override void ProcessRecord() { if (ParameterSpecified(nameof(Store)) && !OperatingSystem.IsWindows()) { throw new PSArgumentException("The Store parameter is only supported on Microsoft Windows"); } if (!string.IsNullOrWhiteSpace(OutPath)) { if (!Path.IsPathRooted(OutPath)) { OutPath = Path.Combine(SessionState.Path.CurrentFileSystemLocation.Path, OutPath); } } else { OutPath = SessionState.Path.CurrentFileSystemLocation.Path; } var redirectUri = "https://pnp.github.io/powershell/consent.html"; var messageWriter = new CmdletMessageWriter(this); cancellationTokenSource = new CancellationTokenSource(); CancellationToken cancellationToken = cancellationTokenSource.Token; WriteVerbose(ParameterSetName); var loginEndPoint = string.Empty; var record = new PSObject(); using (var authenticationManager = new AuthenticationManager()) { loginEndPoint = authenticationManager.GetAzureADLoginEndPoint(AzureEnvironment); } string token = GetAuthToken(messageWriter, loginEndPoint); if (!string.IsNullOrEmpty(token)) { var cert = GetCertificate(record); using (var httpClient = new HttpClient()) { if (!AppExists(ApplicationName, httpClient, token)) { var azureApp = CreateApp(loginEndPoint, httpClient, token, cert, redirectUri); record.Properties.Add(new PSVariableProperty(new PSVariable("AzureAppId/ClientId", azureApp.AppId))); record.Properties.Add(new PSVariableProperty(new PSVariable("Certificate Thumbprint", cert.GetCertHashString()))); StartConsentFlow(loginEndPoint, azureApp, redirectUri, token, httpClient, record); } else { throw new PSInvalidOperationException($"The application with name {ApplicationName} already exists."); } } } }
private X509Certificate2 GetCertificate(PSObject record) { var cert = new X509Certificate2(); if (ParameterSetName == ParameterSet_EXISTINGCERT) { if (!System.IO.Path.IsPathRooted(CertificatePath)) { CertificatePath = Path.Combine(SessionState.Path.CurrentFileSystemLocation.Path, CertificatePath); } // Ensure a file exists at the provided CertificatePath if (!File.Exists(CertificatePath)) { throw new PSArgumentException(string.Format(Resources.CertificateNotFoundAtPath, CertificatePath), nameof(CertificatePath)); } try { cert = new X509Certificate2(CertificatePath, CertificatePassword, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet); } catch (CryptographicException e) when(e.Message.Contains("The specified password is not correct")) { throw new PSArgumentNullException(nameof(CertificatePassword), string.Format(Resources.PrivateKeyCertificateImportFailedPasswordIncorrect, nameof(CertificatePassword))); } // Ensure the certificate at the provided CertificatePath holds a private key if (!cert.HasPrivateKey) { throw new PSArgumentException(string.Format(Resources.CertificateAtPathHasNoPrivateKey, CertificatePath), nameof(CertificatePath)); } } else { #if NETFRAMEWORK var x500Values = new List <string>(); if (!MyInvocation.BoundParameters.ContainsKey("CommonName")) { CommonName = ApplicationName; } if (!string.IsNullOrWhiteSpace(CommonName)) { x500Values.Add($"CN={CommonName}"); } if (!string.IsNullOrWhiteSpace(Country)) { x500Values.Add($"C={Country}"); } if (!string.IsNullOrWhiteSpace(State)) { x500Values.Add($"S={State}"); } if (!string.IsNullOrWhiteSpace(Locality)) { x500Values.Add($"L={Locality}"); } if (!string.IsNullOrWhiteSpace(Organization)) { x500Values.Add($"O={Organization}"); } if (!string.IsNullOrWhiteSpace(OrganizationUnit)) { x500Values.Add($"OU={OrganizationUnit}"); } string x500 = string.Join("; ", x500Values); if (ValidYears < 1 || ValidYears > 30) { ValidYears = 10; } DateTime validFrom = DateTime.Today; DateTime validTo = validFrom.AddYears(ValidYears); byte[] certificateBytes = CertificateHelper.CreateSelfSignCertificatePfx(x500, validFrom, validTo, CertificatePassword); cert = new X509Certificate2(certificateBytes, CertificatePassword, X509KeyStorageFlags.Exportable | X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet); #else if (!MyInvocation.BoundParameters.ContainsKey("CommonName")) { CommonName = ApplicationName; } DateTime validFrom = DateTime.Today; DateTime validTo = validFrom.AddYears(ValidYears); cert = CertificateHelper.CreateSelfSignedCertificate(CommonName, Country, State, Locality, Organization, OrganizationUnit, CertificatePassword, CommonName, validFrom, validTo); #endif } var pfxPath = string.Empty; var cerPath = string.Empty; if (Directory.Exists(OutPath)) { pfxPath = Path.Combine(OutPath, $"{ApplicationName}.pfx"); cerPath = Path.Combine(OutPath, $"{ApplicationName}.cer"); byte[] certPfxData = cert.Export(X509ContentType.Pfx, CertificatePassword); File.WriteAllBytes(pfxPath, certPfxData); record.Properties.Add(new PSVariableProperty(new PSVariable("Pfx file", pfxPath))); byte[] certCerData = cert.Export(X509ContentType.Cert); File.WriteAllBytes(cerPath, certCerData); record.Properties.Add(new PSVariableProperty(new PSVariable("Cer file", cerPath))); } if (ParameterSpecified(nameof(Store))) { if (OperatingSystem.IsWindows()) { using (var store = new X509Store("My", Store)) { store.Open(OpenFlags.ReadWrite); store.Add(cert); store.Close(); } Host.UI.WriteLine(ConsoleColor.Yellow, Host.UI.RawUI.BackgroundColor, "Certificate added to store"); } } return(cert); }
protected override void ProcessRecord() { if (ParameterSpecified(nameof(Store)) && !OperatingSystem.IsWindows()) { throw new PSArgumentException("The Store parameter is only supported on Microsoft Windows"); } if (!string.IsNullOrWhiteSpace(OutPath)) { if (!Path.IsPathRooted(OutPath)) { OutPath = Path.Combine(SessionState.Path.CurrentFileSystemLocation.Path, OutPath); } } else { OutPath = SessionState.Path.CurrentFileSystemLocation.Path; } var redirectUri = "http://localhost"; if (ParameterSpecified(nameof(DeviceLogin))) { redirectUri = "https://pnp.github.io/powershell/consent.html"; } var messageWriter = new CmdletMessageWriter(this); cancellationTokenSource = new CancellationTokenSource(); CancellationToken cancellationToken = cancellationTokenSource.Token; var loginEndPoint = string.Empty; using (var authenticationManager = new AuthenticationManager()) { loginEndPoint = authenticationManager.GetAzureADLoginEndPoint(AzureEnvironment); } var permissionScopes = new PermissionScopes(); var scopes = new List <PermissionScope>(); if (this.Scopes != null) { foreach (var scopeIdentifier in this.Scopes) { scopes.Add(permissionScopes.GetScope(scopeIdentifier)); } } else { scopes.Add(permissionScopes.GetScope("SPO.Sites.FullControl.All")); scopes.Add(permissionScopes.GetScope("MSGraph.Group.ReadWrite.All")); scopes.Add(permissionScopes.GetScope("SPO.User.Read.All")); scopes.Add(permissionScopes.GetScope("MSGraph.User.Read.All")); } var record = new PSObject(); string token = GetAuthToken(messageWriter); if (!string.IsNullOrEmpty(token)) { var cert = GetCertificate(record); using (var httpClient = new HttpClient()) { if (!AppExists(ApplicationName, httpClient, token)) { var azureApp = CreateApp(loginEndPoint, httpClient, token, cert, redirectUri, scopes); record.Properties.Add(new PSVariableProperty(new PSVariable("AzureAppId/ClientId", azureApp.AppId))); record.Properties.Add(new PSVariableProperty(new PSVariable("Certificate Thumbprint", cert.GetCertHashString()))); byte[] certPfxData = cert.Export(X509ContentType.Pfx, CertificatePassword); var base64String = Convert.ToBase64String(certPfxData); record.Properties.Add(new PSVariableProperty(new PSVariable("Base64Encoded", base64String))); StartConsentFlow(loginEndPoint, azureApp, redirectUri, token, httpClient, record, messageWriter, scopes); } else { throw new PSInvalidOperationException($"The application with name {ApplicationName} already exists."); } } } }