protected override async Task <HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken) { var realmService = new FakeRealmService(Realm); var principal = await realmService.Principals.Find(UserUpn); var principalKey = await principal.RetrieveLongTermCredential(); var rst = new ServiceTicketRequest { Principal = principal, EncryptedPartKey = principalKey, ServicePrincipalKey = new KerberosKey(key: TgtKey, etype: EncryptionType.AES256_CTS_HMAC_SHA1_96) }; var tgt = await KrbAsRep.GenerateTgt(rst, realmService); var encoded = tgt.EncodeApplication(); var response = new Memory <byte>(new byte[encoded.Length + 4]); Endian.ConvertToBigEndian(encoded.Length, response.Slice(0, 4)); encoded.CopyTo(response.Slice(4)); var kdcMessage = new KdcProxyMessage { KerbMessage = response }; return(new HttpResponseMessage(HttpStatusCode.OK) { Content = new ByteArrayContent(kdcMessage.Encode().ToArray()) }); }
private ReadOnlyMemory <byte> GenerateAsRep(KrbAsReq asReq, PreAuthenticationContext context) { // 1. detect if specific PAC contents are requested (claims) // 2. if requested generate PAC for user // 3. stuff PAC into ad-if-relevant pa-data of krbtgt ticket // 4. look up krbtgt account // 5. encrypt against krbtgt // 6. done var rst = new ServiceTicketRequest { Principal = context.Principal, EncryptedPartKey = context.EncryptedPartKey, ServicePrincipal = context.ServicePrincipal, Addresses = asReq.Body.Addresses, Nonce = asReq.Body.Nonce, IncludePac = true, Flags = TicketFlags.Initial | KrbKdcRep.DefaultFlags }; if (!asReq.Body.KdcOptions.HasFlag(KdcOptions.Canonicalize)) { rst.SamAccountName = asReq.Body.CName.FullyQualifiedName; } if (context.ClientAuthority != PaDataType.PA_NONE) { rst.Flags |= TicketFlags.PreAuthenticated; } if (rst.EncryptedPartKey == null) { rst.EncryptedPartKey = rst.Principal.RetrieveLongTermCredential(); } rst.IncludePac = DetectPacRequirement(asReq) ?? false; var asRep = KrbAsRep.GenerateTgt(rst, RealmService); if (context.PaData != null) { asRep.PaData = context.PaData.ToArray(); } return(asRep.EncodeApplication()); }
private async Task <ReadOnlyMemory <byte> > GenerateAsRep(KrbAsReq asReq, IKerberosPrincipal principal) { // 1. detect if specific PAC contents are requested (claims) // 2. if requested generate PAC for user // 3. stuff PAC into ad-if-relevant pa-data of krbtgt ticket // 4. look up krbtgt account // 5. encrypt against krbtgt // 6. done var requirements = new List <KrbPaData>(); foreach (var handler in postProcessAuthHandlers) { await InvokePreAuthHandler(null, principal, requirements, handler.Value); } var rst = new ServiceTicketRequest { Principal = principal, Addresses = asReq.Body.Addresses, Nonce = asReq.Body.Nonce, IncludePac = true, Flags = TicketFlags.Initial | KrbKdcRep.DefaultFlags }; rst.EncryptedPartKey = await principal.RetrieveLongTermCredential(); var pacRequest = asReq.PaData.FirstOrDefault(pa => pa.Type == PaDataType.PA_PAC_REQUEST); if (pacRequest != null) { var paPacRequest = KrbPaPacRequest.Decode(pacRequest.Value); rst.IncludePac = paPacRequest.IncludePac; } var asRep = await KrbAsRep.GenerateTgt(rst, RealmService); asRep.PaData = requirements.ToArray(); return(asRep.EncodeApplication()); }
private async Task <ReadOnlyMemory <byte> > GenerateAsRep(PreAuthenticationContext preauth, KrbAsReq asReq) { // 1. detect if specific PAC contents are requested (claims) // 2. if requested generate PAC for user // 3. stuff PAC into ad-if-relevant pa-data of krbtgt ticket // 4. look up krbtgt account // 5. encrypt against krbtgt // 6. done var rst = new ServiceTicketRequest { Principal = preauth.Principal, EncryptedPartKey = preauth.EncryptedPartKey, Addresses = asReq.Body.Addresses, Nonce = asReq.Body.Nonce, IncludePac = true, Flags = TicketFlags.Initial | KrbKdcRep.DefaultFlags }; if (rst.EncryptedPartKey == null) { rst.EncryptedPartKey = await rst.Principal.RetrieveLongTermCredential(); } var pacRequest = asReq.PaData.FirstOrDefault(pa => pa.Type == PaDataType.PA_PAC_REQUEST); if (pacRequest != null) { var paPacRequest = KrbPaPacRequest.Decode(pacRequest.Value); rst.IncludePac = paPacRequest.IncludePac; } var asRep = await KrbAsRep.GenerateTgt(rst, RealmService); if (preauth.PaData != null) { asRep.PaData = preauth.PaData.ToArray(); } return(asRep.EncodeApplication()); }
private async Task <ReadOnlyMemory <byte> > GenerateAsRep(KrbKdcReq asReq, IKerberosPrincipal principal) { // 1. detect if specific PAC contents are requested (claims) // 2. if requested generate PAC for user // 3. stuff PAC into ad-if-relevant pa-data of krbtgt ticket // 4. look up krbtgt account // 5. encrypt against krbtgt // 6. done var requirements = new List <KrbPaData>(); foreach (var handler in postProcessAuthHandlers) { await InvokePreAuthHandler(null, principal, requirements, handler.Value); } var asRep = await KrbAsRep.GenerateTgt(principal, requirements, RealmService, asReq.Body); return(asRep.EncodeApplication()); }
public void GenerateTgt() { var realmService = new FakeRealmService(Realm); var principal = realmService.Principals.Find(KrbPrincipalName.FromString(UserUpn)); var principalKey = principal.RetrieveLongTermCredential(); var rst = new ServiceTicketRequest { Flags = TicketFlags.EncryptedPreAuthentication | TicketFlags.Renewable | TicketFlags.Forwardable, Principal = principal, EncryptedPartKey = principalKey, ServicePrincipalKey = new KerberosKey(key: TgtKey, etype: etype, kvno: 123) }; for (var i = 0; i < AuthenticationAttempts; i++) { var tgt = KrbAsRep.GenerateTgt(rst, realmService); Assert.IsNotNull(tgt); } }
public void GeneratedTgtMatchesActiveDirectory() { var realmService = new FakeRealmService(Realm); var principal = realmService.Principals.Find(KrbPrincipalName.FromString(UserUpn)); var principalKey = principal.RetrieveLongTermCredential(); var rst = new ServiceTicketRequest { Flags = ExpectedFlags, Principal = principal, EncryptedPartKey = principalKey, ServicePrincipalKey = new KerberosKey(key: TgtKey, etype: EncryptionType.AES256_CTS_HMAC_SHA1_96) }; var tgt = KrbAsRep.GenerateTgt(rst, realmService); Assert.IsNotNull(tgt); var encoded = tgt.EncodeApplication(); AssertIsExpectedKrbtgt(principalKey, rst.ServicePrincipalKey, encoded.ToArray()); }
public async Task GeneratedTgtMatchesWithOnPremisesSamAccountName() { var realmService = new FakeRealmService(Realm); var principal = await realmService.Principals.Find(UserUpn); var principalKey = await principal.RetrieveLongTermCredential(); var rst = new ServiceTicketRequest { SamAccountName = TestSamAccountName, Flags = ExpectedFlags, Principal = principal, EncryptedPartKey = principalKey, ServicePrincipalKey = new KerberosKey(key: TgtKey, etype: EncryptionType.AES256_CTS_HMAC_SHA1_96) }; var tgt = await KrbAsRep.GenerateTgt(rst, realmService); Assert.IsNotNull(tgt); var encoded = tgt.EncodeApplication(); AssertIsExpectedKrbtgtWithOnPremisesSamAccountName(principalKey, rst.ServicePrincipalKey, encoded.ToArray()); }
public void GeneratedTgtMatchesWithOnPremisesSamAccountName(string realm, KerberosCompatibilityFlags compatibilityFlags, string expectedRealm) { var realmService = new FakeRealmService(realm, compatibilityFlags: compatibilityFlags); var principal = realmService.Principals.Find(KrbPrincipalName.FromString(UserUpn)); var principalKey = principal.RetrieveLongTermCredential(); var rst = new ServiceTicketRequest { SamAccountName = TestSamAccountName, Flags = ExpectedFlags, Principal = principal, EncryptedPartKey = principalKey, ServicePrincipalKey = new KerberosKey(key: TgtKey, etype: EncryptionType.AES256_CTS_HMAC_SHA1_96) }; var tgt = KrbAsRep.GenerateTgt(rst, realmService); Assert.IsNotNull(tgt); var encoded = tgt.EncodeApplication(); AssertIsExpectedKrbtgtWithOnPremisesSamAccountName(principalKey, rst.ServicePrincipalKey, encoded.ToArray(), expectedRealm); }
private ReadOnlyMemory <byte> GenerateAsRep(KrbAsReq asReq, PreAuthenticationContext context) { // 1. detect if specific PAC contents are requested (claims) // 2. if requested generate PAC for user // 3. stuff PAC into ad-if-relevant pa-data of krbtgt ticket // 4. look up krbtgt account // 5. encrypt against krbtgt // 6. done var rst = new ServiceTicketRequest { Principal = context.Principal, EncryptedPartKey = context.EncryptedPartKey, EncryptedPartEType = context.EncryptedPartEType, ServicePrincipal = context.ServicePrincipal, Addresses = asReq.Body.Addresses, Nonce = asReq.Body.Nonce, Now = this.RealmService.Now(), StartTime = asReq.Body.From ?? DateTimeOffset.MinValue, EndTime = asReq.Body.Till, MaximumTicketLifetime = this.RealmService.Settings.SessionLifetime, Flags = TicketFlags.Initial | KrbKdcRep.DefaultFlags, PreferredClientEType = GetPreferredEType( asReq.Body.EType, this.RealmService.Configuration.Defaults.PermittedEncryptionTypes, this.RealmService.Configuration.Defaults.AllowWeakCrypto ), Compatibility = this.RealmService.Settings.Compatibility, }; if (context.ClientAuthority != PaDataType.PA_NONE) { rst.Flags |= TicketFlags.PreAuthenticated; } // Canonicalize means the CName in the reply is allowed to be different from the CName in the request. // If this is not allowed, then we must use the CName from the request. Otherwise, we will set the CName // to what we have in our realm, i.e. user@realm. if (!asReq.Body.KdcOptions.HasFlag(KdcOptions.Canonicalize)) { rst.SamAccountName = asReq.Body.CName.FullyQualifiedName; } if (rst.EncryptedPartKey == null) { rst.EncryptedPartKey = rst.Principal.RetrieveLongTermCredential(); } if (context.IncludePac == null) { context.IncludePac = DetectPacRequirement(asReq); } rst.IncludePac = context.IncludePac ?? false; // this is set here instead of in GenerateServiceTicket because GST is used by unit tests to // generate tickets with weird lifetimes for scenario testing and we don't want to break that rst.ClampLifetime(); var asRep = KrbAsRep.GenerateTgt(rst, this.RealmService); if (context.PaData != null) { asRep.PaData = context.PaData.ToArray(); } return(asRep.EncodeApplication()); }