/// <summary> /// Constructor. /// </summary> /// <param name="attributes">the attributes for server</param> /// <param name="nlmpConfig"> /// the config for nlmp client, this param maybe null. if null, spng does not support nlmp. /// </param> /// <param name="kileConfig"> /// the config for kile client, this param maybe null. if null, spng does not support Kerberos. /// </param> /// <exception cref="ArgumentException">at least one of nlmpConfig and kileConfig must not be null</exception> public SpngClientSecurityContext( ClientSecurityContextAttribute attributes, NlmpClientSecurityConfig nlmpConfig, KerberosClientSecurityConfig kileConfig) { InitializeClientSecurityContext(attributes, nlmpConfig, kileConfig, null); }
/// <summary> /// initialize the client security context. /// </summary> /// <param name="attributes">the attributes for server</param> /// <param name="nlmpConfig"> /// the config for nlmp client, this param maybe null. if null, spng does not support nlmp. /// </param> /// <param name="kileConfig"> /// the config for kile client, this param maybe null. if null, spng does not support Kerberos. /// </param> /// <param name="sspiConfig"> /// the config for sspi client, this param maybe null. if null, spng does not support sspi. /// </param> /// <exception cref="ArgumentException"> /// at least one of nlmpConfig, kileConfig and sspiConfig must not be null /// </exception> private void InitializeClientSecurityContext( ClientSecurityContextAttribute attributes, NlmpClientSecurityConfig nlmpConfig, KerberosClientSecurityConfig kileConfig, SspiClientSecurityConfig sspiConfig) { if (nlmpConfig == null && kileConfig == null && sspiConfig == null) { throw new ArgumentException("at least one of nlmpConfig, kileConfig and sspiConfig must not be null"); } List <SecurityConfig> configList = new List <SecurityConfig>(); // build the mech types List <MechType> mechTypes = new List <MechType>(); if (kileConfig != null) { configList.Add(kileConfig); mechTypes.Add(new MechType(Consts.KerbOidInt)); } if (nlmpConfig != null) { configList.Add(nlmpConfig); mechTypes.Add(new MechType(Consts.NlmpOidInt)); } if (sspiConfig != null) { configList.Add(sspiConfig); switch (sspiConfig.SecurityType) { case SecurityPackageType.Ntlm: mechTypes.Add(new MechType(Consts.NlmpOidInt)); break; case SecurityPackageType.Kerberos: mechTypes.Add(new MechType(Consts.KerbOidInt)); break; default: mechTypes.Add(new MechType(Consts.UnknownOidInt)); break; } } // build a spng config SpngClientSecurityConfig spngConfig = new SpngClientSecurityConfig(attributes, new MechTypeList(mechTypes.ToArray())); // add spng config to config list. configList.Insert(0, spngConfig); // initialize the spng client this.client = new SpngClient(spngConfig); this.needContinueProcessing = true; this.packageType = SecurityPackageType.Negotiate; this.securityConfigList = configList.ToArray(); }
/// <summary> /// Initialize the securityMechContext based on the security package type /// </summary> /// <param name="mechType">security mechanism type</param> /// <param name="inToken">the input security token</param> /// <exception cref="InvalidOperationException">Thrown if could not find the configuration.</exception> /// <exception cref="InvalidOperationException">Thrown when security configuration is unknown</exception> private void InitializeSecurityContext(MechType mechType, byte[] inToken) { SpngClientContext clientContext = this.client.Context as SpngClientContext; SecurityPackageType authType = SpngUtility.ConvertMechType(mechType); CurrentSecurityConfig = SpngUtility.GetSecurityConfig(this.securityConfigList, authType); if (CurrentSecurityConfig == null) { throw new InvalidOperationException("Missing configuration for " + authType.ToString()); } if (securityMechContext != null) { // re-enter. Nothing need to do return; } if (CurrentSecurityConfig.GetType() == typeof(KerberosClientSecurityConfig)) { KerberosClientSecurityConfig kileConfig = CurrentSecurityConfig as KerberosClientSecurityConfig; securityMechContext = new KerberosClientSecurityContext( kileConfig.ServiceName, kileConfig.ClientCredential, KerberosAccountType.User, kileConfig.KdcIpAddress, kileConfig.KdcPort, kileConfig.TransportType, kileConfig.SecurityAttributes); } else if (CurrentSecurityConfig.GetType() == typeof(NlmpClientSecurityConfig)) { NlmpClientSecurityConfig nlmpConfig = CurrentSecurityConfig as NlmpClientSecurityConfig; NlmpClientCredential cred = new NlmpClientCredential( nlmpConfig.TargetName, nlmpConfig.DomainName, nlmpConfig.AccountName, nlmpConfig.Password); securityMechContext = new NlmpClientSecurityContext(cred, nlmpConfig.SecurityAttributes); } else if (CurrentSecurityConfig.GetType() == typeof(SspiClientSecurityConfig)) { throw new InvalidOperationException("Only support Kerberos security config and NTLM security config"); } else { throw new InvalidOperationException("unknown security config"); } }
private void SpngNegotiationAcceptIncomplete(byte[] inToken) { byte[] securityToken = null; bool isNeedWrap = true; if ((inToken == null) || (inToken.Length == 0)) { throw new ArgumentNullException("inToken"); } byte[] mechListMic = null; if (CurrentSecurityConfig.GetType() == typeof(NlmpClientSecurityConfig)) { NlmpClientSecurityConfig nlmpConfig = CurrentSecurityConfig as NlmpClientSecurityConfig; if ((nlmpConfig.SecurityAttributes & ClientSecurityContextAttribute.DceStyle) == ClientSecurityContextAttribute.DceStyle) { isNeedWrap = false; } } securityToken = isNeedWrap ? UnwrapNegotiationToken(inToken, out mechListMic) : inToken; if (!securityMechContext.NeedContinueProcessing) { this.needContinueProcessing = false; this.client.Context.NegotiationState = SpngNegotiationState.AcceptCompleted; this.token = null; if (isNeedWrap && mechListMic != null && !this.client.VerifyMechListMIC(securityMechContext, mechListMic)) { throw new InvalidOperationException("Invalid MechListMic"); } } else { securityMechContext.Initialize(securityToken); if (!securityMechContext.NeedContinueProcessing) { this.needMechListMic = true; } this.token = isNeedWrap ? WrapNegotiationToken(SpngPayloadType.NegResp, securityMechContext.Token) : securityMechContext.Token; } }
private void UpdateNegotiationToken(byte[] securityToken) { if (this.client.Context.NegotiationState == SpngNegotiationState.SspiNegotiation) { //SSPI negotiation already has an SPNG wrapper. this.token = securityToken; } else { bool isNeedWrap = true; if (CurrentSecurityConfig.GetType() == typeof(NlmpClientSecurityConfig)) { NlmpClientSecurityConfig nlmpConfig = CurrentSecurityConfig as NlmpClientSecurityConfig; if ((nlmpConfig.SecurityAttributes & ClientSecurityContextAttribute.DceStyle) == ClientSecurityContextAttribute.DceStyle) { isNeedWrap = false; } } this.token = isNeedWrap ? WrapInitialNegToken(securityMechContext.Token) : securityMechContext.Token; } }
/// <summary> /// AcquireCredentialsHandle /// </summary> /// <param name="accountCredential"></param> protected void AcquireCredentialsHandle <T>(T accountCredential) { if (!string.IsNullOrEmpty(this.serverPrincipalName)) { this.serverPrincipalName = GetServicePrincipalName(this.serverPrincipalName); } switch (packageType) { case SecurityPackageType.Ntlm: { if (accountCredential is AccountCredential) { var credential = accountCredential as AccountCredential; this.Context = new NlmpClientSecurityContext( new NlmpClientCredential( this.serverPrincipalName, credential.DomainName, credential.AccountName, credential.Password) ); } else { throw new NotSupportedException("NTLM only support AccountCredential, Please provide an AccountCredential and try again."); } return; } case SecurityPackageType.Kerberos: { if (accountCredential is AccountCredential) { var credential = accountCredential as AccountCredential; IPAddress kdcIpAddress = (string.IsNullOrEmpty(KerberosContext.KDCComputerName) ? credential.DomainName : KerberosContext.KDCComputerName).ParseIPAddress(); this.Context = KerberosClientSecurityContext.CreateClientSecurityContext( this.serverPrincipalName, credential, KerberosAccountType.User, kdcIpAddress, KerberosContext.KDCPort, TransportType.TCP, this.securityContextAttributes ); } else { throw new NotSupportedException("Kerberos only support AccountCredential, Please provide an AccountCredential and try again."); } return; } case SecurityPackageType.Negotiate: { if (accountCredential is AccountCredential) { if (this.securityContextAttributes == ClientSecurityContextAttribute.None) { this.securityContextAttributes = ClientSecurityContextAttribute.MutualAuth; // MS-SPNG 3.3.3 The client MUST request Mutual Authentication services } var credential = accountCredential as AccountCredential; NlmpClientSecurityConfig nlmpSecurityConfig = new NlmpClientSecurityConfig(credential, this.serverPrincipalName, this.securityContextAttributes); IPAddress kdcIpAddress = (string.IsNullOrEmpty(KerberosContext.KDCComputerName) ? credential.DomainName : KerberosContext.KDCComputerName).ParseIPAddress(); KerberosClientSecurityConfig kerberosSecurityConfig = new KerberosClientSecurityConfig( credential, credential.AccountName, this.serverPrincipalName, kdcIpAddress, KerberosContext.KDCPort, this.securityContextAttributes, TransportType.TCP ); this.Context = new SpngClientSecurityContext(this.securityContextAttributes, nlmpSecurityConfig, kerberosSecurityConfig); } else { throw new NotSupportedException("Negotiate SSP only support AccountCredential, Please provide an AccountCredential and try again."); } return; } //case SecurityPackageType.Schannel: // throw new NotImplementedException(); //case SecurityPackageType.CredSsp: // throw new NotImplementedException(); //default: // throw new NotImplementedException(); } this.UseNativeSSP(accountCredential); }
/// <summary> /// Initialize the context from a token, and generate a new token. /// </summary> /// <param name="inToken">the token from server. "inToken" must be null when invoked first time.</param> /// <exception cref="ArgumentNullException">Except invoked at the first time, the "inToken" MUST not be null /// when invoking Initialize.</exception> /// <exception cref="InvalidOperationException">The internal state is invalid when invoking Initialize.</exception> /// <exception cref="InvalidOperationException">Invalid MechListMic</exception> public override void Initialize(byte[] inToken) { byte[] securityToken = null; MechTypeList serverMechList = null; bool isNeedWrap = true; switch (this.client.Context.NegotiationState) { case SpngNegotiationState.Initial: if ((inToken == null) || (inToken.Length == 0)) // Client Initiation Mode { InitializeSecurityContext(this.client.Config.MechList.Elements[0], securityToken); this.client.Context.NegotiationState = SpngNegotiationState.AcceptIncomplete; } else { try { securityToken = UnwrapInitialNegToken2(inToken, out serverMechList); this.client.NegotiateMechType(serverMechList); if (this.client.Context.NegotiationState == SpngNegotiationState.Reject) { //Negotiation failed. Do not need to throw exception in this case. return; } } catch { // check if reauth token SpngNegotiationToken negToken = new SpngNegotiationToken(); negToken.FromBytes(inToken); this.client.Context.NegotiatedMechType = negToken.SupportedMechType; // try use preview MechType to do Re-Initialize securityToken = null; } InitializeSecurityContext(this.client.Context.NegotiatedMechType, securityToken); } if (this.client.Context.NegotiationState == SpngNegotiationState.AcceptIncomplete) // server prefered mechtype can find from local support mechtype list. { try { securityMechContext.Initialize(securityToken); } catch { securityMechContext = null; // try use NTLM InitializeSecurityContext(this.client.Config.MechList.Elements[1], securityToken); this.client.Context.NegotiationState = SpngNegotiationState.AcceptIncomplete; securityMechContext.Initialize(securityToken); } } else { securityMechContext.Initialize(null); } if (this.client.Context.NegotiationState == SpngNegotiationState.SspiNegotiation) { //SSPI negotiation already has an SPNG wrapper. this.token = securityToken; } else { if (CurrentSecurityConfig.GetType() == typeof(NlmpClientSecurityConfig)) { NlmpClientSecurityConfig nlmpConfig = CurrentSecurityConfig as NlmpClientSecurityConfig; if ((nlmpConfig.SecurityAttributes & ClientSecurityContextAttribute.DceStyle) == ClientSecurityContextAttribute.DceStyle) { isNeedWrap = false; } } if (isNeedWrap) { this.token = WrapInitialNegToken(securityMechContext.Token); } else { this.token = securityMechContext.Token; } } break; case SpngNegotiationState.RequestMic: if ((inToken == null) || (inToken.Length == 0)) { throw new ArgumentNullException("inToken"); } securityToken = UnwrapNegotiationToken(inToken); this.needMechListMic = true; this.client.Context.NegotiationState = SpngNegotiationState.AcceptIncomplete; securityMechContext.Initialize(securityToken); if (securityMechContext.Token != null) { this.token = WrapNegotiationToken(SpngPayloadType.NegResp, securityMechContext.Token); } break; case SpngNegotiationState.AcceptIncomplete: if ((inToken == null) || (inToken.Length == 0)) { throw new ArgumentNullException("inToken"); } byte[] mechListMic = null; if (CurrentSecurityConfig.GetType() == typeof(NlmpClientSecurityConfig)) { NlmpClientSecurityConfig nlmpConfig = CurrentSecurityConfig as NlmpClientSecurityConfig; if ((nlmpConfig.SecurityAttributes & ClientSecurityContextAttribute.DceStyle) == ClientSecurityContextAttribute.DceStyle) { isNeedWrap = false; } } if (isNeedWrap) { securityToken = UnwrapNegotiationToken(inToken, out mechListMic); if (!securityMechContext.NeedContinueProcessing) { this.needContinueProcessing = false; this.client.Context.NegotiationState = SpngNegotiationState.AcceptCompleted; this.token = null; if (mechListMic != null && !this.client.VerifyMechListMIC(securityMechContext, mechListMic)) { throw new InvalidOperationException("Invalid MechListMic"); } } else { securityMechContext.Initialize(securityToken); if (!securityMechContext.NeedContinueProcessing) { this.needMechListMic = true; } this.token = WrapNegotiationToken(SpngPayloadType.NegResp, securityMechContext.Token); } } else { this.needContinueProcessing = false; if (!securityMechContext.NeedContinueProcessing) { this.client.Context.NegotiationState = SpngNegotiationState.AcceptCompleted; this.token = null; } else { securityToken = inToken; securityMechContext.Initialize(securityToken); this.token = securityMechContext.Token; } } break; case SpngNegotiationState.AcceptCompleted: throw new InvalidOperationException("Authentication completed!"); case SpngNegotiationState.SspiNegotiation: if (securityMechContext != null) { securityMechContext.Initialize(inToken); } break; default: // MUST be SpngNegotiationState.Reject throw new InvalidOperationException("Authentication rejected!"); } }