wwauth/Google.Solutions.WWAuth/View/AdfsConfigurationViewModel.cs (262 lines of code) (raw):

// // Copyright 2022 Google LLC // // Licensed to the Apache Software Foundation (ASF) under one // or more contributor license agreements. See the NOTICE file // distributed with this work for additional information // regarding copyright ownership. The ASF licenses this file // to you under the Apache License, Version 2.0 (the // "License"); you may not use this file except in compliance // with the License. You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, // software distributed under the License is distributed on an // "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, either express or implied. See the License for the // specific language governing permissions and limitations // under the License. // using Google.Solutions.WWAuth.Adapters; using Google.Solutions.WWAuth.Data; using System; using System.Linq; using System.Security.Cryptography.X509Certificates; using System.Windows.Forms; namespace Google.Solutions.WWAuth.View { internal class AdfsConfigurationViewModel : ConfigurationViewModelBase, IPropertiesSheetViewModel { private readonly ICertificateStoreAdapter certificateStoreAdapter; private readonly UnattendedCommandLineOptions commandLineOptions; private bool isClientIdTextBoxVisible; private bool isRelyingPartyIdTextBoxReadonly; private bool isAcsUrlTextBoxVisible; private bool isSignRequestControlVisible; private bool isSignRequestControlEnabled; private X509Certificate2 requestSigningCertificate; public AdfsConfigurationViewModel( CredentialConfigurationFile file, IShellAdapter shellAdapter, ICertificateStoreAdapter certificateStoreAdapter) : base(file, shellAdapter) { this.commandLineOptions = file.Configuration.Options; this.certificateStoreAdapter = certificateStoreAdapter; if (!string.IsNullOrEmpty(this.commandLineOptions.SamlRequestSigningCertificate)) { this.RequestSigningCertificate = certificateStoreAdapter.TryGetSigningCertificate( this.commandLineOptions.SamlRequestSigningCertificate); } ReapplyProtocolDefaults(); } public string Title => "AD FS"; /// <summary> /// By default, STS expects the provider URL as audience, which /// defines the default relying party ID. /// </summary> internal string DefaultRelyingPartyId => $"https:{this.File.Configuration.PoolConfiguration.Audience}"; //--------------------------------------------------------------------- // Observable properties. //--------------------------------------------------------------------- public string IssuerUrl { get => this.commandLineOptions.IssuerUrl; set { this.commandLineOptions.IssuerUrl = value.Trim(); this.IsDirty = true; RaisePropertyChange(); } } public string[] AvailableProtocols { get => Enum.GetValues(typeof(UnattendedCommandLineOptions.AuthenticationProtocol)) .Cast<UnattendedCommandLineOptions.AuthenticationProtocol>() .Select(v => v.ToString()) .ToArray(); } public int ProtocolIndex { get => Array.IndexOf(this.AvailableProtocols, this.commandLineOptions.Protocol.ToString()); set { this.commandLineOptions.Protocol = (UnattendedCommandLineOptions.AuthenticationProtocol)Enum.Parse( typeof(UnattendedCommandLineOptions.AuthenticationProtocol), this.AvailableProtocols[value]); ReapplyProtocolDefaults(); this.IsDirty = true; RaisePropertyChange(); } } public string RelyingPartyId { get => this.commandLineOptions.RelyingPartyId; set { this.commandLineOptions.RelyingPartyId = value.Trim(); this.IsDirty = true; RaisePropertyChange(); } } public string ClientId { get => this.commandLineOptions.OidcClientId; set { this.commandLineOptions.OidcClientId = value.Trim(); this.IsDirty = true; RaisePropertyChange(); } } public string AcsUrl { get => this.commandLineOptions.SamlAcsUrl; set { this.commandLineOptions.SamlAcsUrl = value.Trim(); this.IsDirty = true; RaisePropertyChange(); } } public bool IsClientIdTextBoxVisible { get => this.isClientIdTextBoxVisible; set { this.isClientIdTextBoxVisible = value; RaisePropertyChange(); } } public bool IsRelyingPartyIdTextBoxReadonly { get => this.isRelyingPartyIdTextBoxReadonly; set { this.isRelyingPartyIdTextBoxReadonly = value; RaisePropertyChange(); } } public bool IsAcsUrlTextBoxVisible { get => this.isAcsUrlTextBoxVisible; set { this.isAcsUrlTextBoxVisible = value; RaisePropertyChange(); } } public bool IsSignRequestControlVisible { get => this.isSignRequestControlVisible; set { this.isSignRequestControlVisible = value; RaisePropertyChange(); } } public bool IsSignRequestControlEnabled { get => this.isSignRequestControlEnabled; set { this.isSignRequestControlEnabled = value; if (!value) { this.RequestSigningCertificate = null; } RaisePropertyChange(); } } public X509Certificate2 RequestSigningCertificate { get => this.requestSigningCertificate; set { this.commandLineOptions.SamlRequestSigningCertificate = value?.Thumbprint; this.requestSigningCertificate = value; if (value != null) { this.IsSignRequestControlEnabled = true; } this.IsDirty = true; RaisePropertyChange(); RaisePropertyChange((AdfsConfigurationViewModel m) => m.SigningCertificateSubject); RaisePropertyChange((AdfsConfigurationViewModel m) => m.IsViewCertificateMenuItemEnabled); } } public string SigningCertificateSubject => this.RequestSigningCertificate?.Subject; public bool IsViewCertificateMenuItemEnabled => this.RequestSigningCertificate != null; public string Executable => this.File.Configuration.Options.Executable; //--------------------------------------------------------------------- // Actions. //--------------------------------------------------------------------- public void ResetExecutable() { this.File.Configuration.ResetExecutable(); this.IsDirty = true; } public void ReapplyProtocolDefaults() { // // N.B. Because some defaults depend on settings controlled by // other property sheet pages, we need to reapply the default // when switching to this sheet and before saving. // switch (this.commandLineOptions.Protocol) { case UnattendedCommandLineOptions.AuthenticationProtocol.AdfsOidc: this.IsRelyingPartyIdTextBoxReadonly = false; if (string.IsNullOrEmpty(this.RelyingPartyId) && this.File.Configuration.PoolConfiguration.IsValid) { this.RelyingPartyId = $"https:{this.File.Configuration.PoolConfiguration.Audience}"; } this.IsClientIdTextBoxVisible = true; this.IsAcsUrlTextBoxVisible = false; if (!string.IsNullOrEmpty(this.AcsUrl)) { this.AcsUrl = string.Empty; } this.IsSignRequestControlVisible = false; break; case UnattendedCommandLineOptions.AuthenticationProtocol.AdfsWsTrust: this.IsRelyingPartyIdTextBoxReadonly = true; this.RelyingPartyId = this.DefaultRelyingPartyId; this.IsClientIdTextBoxVisible = false; if (!string.IsNullOrEmpty(this.ClientId)) { this.ClientId = string.Empty; } this.IsAcsUrlTextBoxVisible = false; if (!string.IsNullOrEmpty(this.AcsUrl)) { this.AcsUrl = string.Empty; } this.IsSignRequestControlVisible = false; break; case UnattendedCommandLineOptions.AuthenticationProtocol.AdfsSamlPost: this.IsRelyingPartyIdTextBoxReadonly = true; this.RelyingPartyId = this.DefaultRelyingPartyId; this.IsClientIdTextBoxVisible = false; if (!string.IsNullOrEmpty(this.ClientId)) { this.ClientId = string.Empty; } this.IsAcsUrlTextBoxVisible = true; if (string.IsNullOrEmpty(this.AcsUrl)) { this.AcsUrl = StsAdapter.DefaultTokenUrl; } this.IsSignRequestControlVisible = true; this.IsSignRequestControlEnabled = this.RequestSigningCertificate != null; break; } } public void BrowseForRequestSigningCertificate( IWin32Window parent) { var candidates = new X509Certificate2Collection(); candidates.AddRange(this.certificateStoreAdapter .ListSigningCertitficates() .ToArray()); var certificate = X509Certificate2UI.SelectFromCollection( candidates, "Signing certificate", "Select a cerfificate", X509SelectionFlag.SingleSelection, parent.Handle) .Cast<X509Certificate2>() .FirstOrDefault(); if (certificate != null) { this.RequestSigningCertificate = certificate; } } public void ViewRequestSigningCertificate( IWin32Window parent) { X509Certificate2UI.DisplayCertificate( this.RequestSigningCertificate, parent.Handle); } public override DialogResult ApplyChanges(IWin32Window owner) { ReapplyProtocolDefaults(); return base.ApplyChanges(owner); } } }