protected override async Task <ReadOnlyMemory <byte> > ExecuteCore(IKerberosMessage message)
        {
            // 1. check what pre-auth validation is required for user
            // 2. enumerate all pre-auth handlers that are available
            //      - fail hard if required doesn't intersect available
            // 3. if pre-auth is required and not present, return error prompting for it
            // 4. if pre-auth is present, validate it
            // 5. if pre-auth failed, return error
            // 6. if some pre-auth succeeded, return error
            // 7. if all required validation succeeds, generate PAC, TGT, and return it

            KrbAsReq asReq = (KrbAsReq)message;

            var principal = await RealmService.Principals.Find(asReq.Body.CName.FullyQualifiedName);

            try
            {
                var preAuthRequests = await ProcessPreAuth(asReq, principal);

                if (preAuthRequests.Count() > 0)
                {
                    return(RequirePreAuth(preAuthRequests, principal));
                }
            }
            catch (KerberosValidationException kex)
            {
                Log(kex);

                return(PreAuthFailed(kex, principal));
            }

            return(await GenerateAsRep(asReq, principal));
        }
Beispiel #2
0
        public override async Task <ReadOnlyMemory <byte> > ExecuteCore(IKerberosMessage message, PreAuthenticationContext context)
        {
            // 1. check what pre-auth validation is required for user
            // 2. enumerate all pre-auth handlers that are available
            //      - fail hard if required doesn't intersect available
            // 3. if pre-auth is required and not present, return error prompting for it
            // 4. if pre-auth is present, validate it
            // 5. if pre-auth failed, return error
            // 6. if some pre-auth succeeded, return error
            // 7. if all required validation succeeds, generate PAC, TGT, and return it

            if (context.Failure != null)
            {
                return(PreAuthFailed(context));
            }

            KrbAsReq asReq = (KrbAsReq)message;

            if (context.Principal == null)
            {
                logger.LogInformation("User {User} not found in realm {Realm}", asReq.Body.CName.FullyQualifiedName, RealmService.Name);

                return(GenerateError(KerberosErrorCode.KDC_ERR_S_PRINCIPAL_UNKNOWN, null, RealmService.Name, asReq.Body.CName.FullyQualifiedName));
            }

            if (!context.PreAuthenticationSatisfied)
            {
                return(RequirePreAuth(context));
            }

            return(await GenerateAsRep(context, asReq));
        }
        protected override async Task <ReadOnlyMemory <byte> > ExecuteCore(IKerberosMessage message)
        {
            // 1. check what pre-auth validation is required for user
            // 2. enumerate all pre-auth handlers that are available
            //      - fail hard if required doesn't intersect available
            // 3. if pre-auth is required and not present, return error prompting for it
            // 4. if pre-auth is present, validate it
            // 5. if pre-auth failed, return error
            // 6. if some pre-auth succeeded, return error
            // 7. if all required validation succeeds, generate PAC, TGT, and return it

            KrbAsReq asReq = (KrbAsReq)message;

            var username = asReq.Body.CName.FullyQualifiedName;

            var principal = await RealmService.Principals.Find(username);

            if (principal == null)
            {
                logger.LogInformation("User {User} not found in realm {Realm}", username, RealmService.Name);

                return(GenerateError(KerberosErrorCode.KDC_ERR_S_PRINCIPAL_UNKNOWN, null, RealmService.Name, username));
            }

            var preauth = new PreAuthenticationContext
            {
                Principal = principal
            };

            try
            {
                var preAuthRequests = await ProcessPreAuth(preauth, asReq);

                if (preAuthRequests.Count() > 0)
                {
                    return(RequirePreAuth(preAuthRequests, principal));
                }
            }
            catch (KerberosValidationException kex)
            {
                logger.LogWarning(kex, "AS-REQ failed processing for principal {Principal}", principal);

                return(PreAuthFailed(kex, principal));
            }

            return(await GenerateAsRep(preauth, asReq));
        }
Beispiel #4
0
        public override async Task <PreAuthenticationContext> ValidateTicketRequest(IKerberosMessage message)
        {
            KrbAsReq asReq = (KrbAsReq)message;

            await SetRealmContext(asReq.Realm);

            var username = asReq.Body.CName.FullyQualifiedName;

            var principal = await RealmService.Principals.Find(username);

            var preauth = new PreAuthenticationContext {
                Principal = principal
            };

            if (preauth.Principal == null)
            {
                return(preauth);
            }

            try
            {
                var preauthReq = await ProcessPreAuth(preauth, asReq);

                if (preauth.PaData == null)
                {
                    preauth.PaData = Array.Empty <KrbPaData>();
                }

                preauth.PaData = preauth.PaData.Union(preauthReq).ToArray();
            }
            catch (KerberosValidationException kex)
            {
                logger.LogWarning(kex, "AS-REQ failed processing for principal {Principal}", principal);

                preauth.Failure = kex;
            }

            return(preauth);
        }
Beispiel #5
0
        public override async Task <PreAuthenticationContext> ValidateTicketRequest(IKerberosMessage message)
        {
            var tgsReq = (KrbTgsReq)message;

            await SetRealmContext(tgsReq.Realm);

            var apReq = ExtractApReq(tgsReq);

            var krbtgtIdentity = await RealmService.Principals.RetrieveKrbtgt();

            var krbtgtKey = await krbtgtIdentity.RetrieveLongTermCredential();

            var krbtgtApReqDecrypted = DecryptApReq(apReq, krbtgtKey);

            var principal = await RealmService.Principals.Find(krbtgtApReqDecrypted.Ticket.CName.FullyQualifiedName);

            return(new PreAuthenticationContext
            {
                Principal = principal,
                EncryptedPartKey = krbtgtApReqDecrypted.SessionKey,
                Ticket = krbtgtApReqDecrypted.Ticket
            });
        }
Beispiel #6
0
        public override async Task <ReadOnlyMemory <byte> > ExecuteCore(IKerberosMessage message, PreAuthenticationContext context)
        {
            // the logic for a TGS-REQ is relatively simple in the primary case where you have a TGT and want
            // to get a ticket to another service. It gets a bit more complicated when you need to do something
            // like a U2U exchange, renew, or get a referral to another realm. Realm referral isn't supported yet.

            // 1. Get the ApReq (TGT) from the PA-Data of the request
            // 2. Decrypt the TGT and extract the client calling identity
            // 3. Find the requested service principal
            // 4. Evaluate whether the client identity should get a ticket to the service
            // 5. Evaluate whether it should do U2U and if so extract that key instead
            // 6. Generate a service ticket for the calling client to the service
            // 7. return to client

            var tgsReq = (KrbTgsReq)message;

            logger.LogInformation("TGS-REQ incoming. SPN = {SPN}", tgsReq.Body.SName.FullyQualifiedName);

            var krbtgtIdentity = await RealmService.Principals.RetrieveKrbtgt();

            var krbtgtKey = await krbtgtIdentity.RetrieveLongTermCredential();

            var servicePrincipal = await RealmService.Principals.Find(tgsReq.Body.SName.FullyQualifiedName);

            // renewal is an odd case here because the SName will be krbtgt
            // does this need to be validated more than the Decrypt call?

            await EvaluateSecurityPolicy(context.Principal, servicePrincipal);

            KerberosKey serviceKey;

            if (tgsReq.Body.KdcOptions.HasFlag(KdcOptions.EncTktInSkey))
            {
                serviceKey = GetUserToUserTicketKey(tgsReq.Body.AdditionalTickets, krbtgtKey);
            }
            else
            {
                serviceKey = await servicePrincipal.RetrieveLongTermCredential();
            }

            var now = RealmService.Now();

            TicketFlags flags = 0;

            if (tgsReq.Body.KdcOptions.HasFlag(KdcOptions.Forwardable))
            {
                flags |= TicketFlags.Forwardable;
            }

            if (context.Ticket.Flags.HasFlag(TicketFlags.PreAuthenticated))
            {
                flags |= TicketFlags.PreAuthenticated;
            }

            var tgsRep = await KrbKdcRep.GenerateServiceTicket <KrbTgsRep>(
                new ServiceTicketRequest
            {
                Principal           = context.Principal,
                EncryptedPartKey    = context.EncryptedPartKey,
                ServicePrincipal    = servicePrincipal,
                ServicePrincipalKey = serviceKey,
                RealmName           = RealmService.Name,
                Addresses           = tgsReq.Body.Addresses,
                RenewTill           = context.Ticket.RenewTill,
                StartTime           = now - RealmService.Settings.MaximumSkew,
                EndTime             = now + RealmService.Settings.SessionLifetime,
                Flags      = flags,
                Now        = now,
                Nonce      = tgsReq.Body.Nonce,
                IncludePac = context.Ticket.AuthorizationData.Any(a => a.Type == AuthorizationDataType.AdIfRelevant)
            }
                );

            return(tgsRep.EncodeApplication());
        }
Beispiel #7
0
        protected override async Task <ReadOnlyMemory <byte> > ExecuteCore(IKerberosMessage message)
        {
            // the logic for a TGS-REQ is relatively simple in the primary case where you have a TGT and want
            // to get a ticket to another service. It gets a bit more complicated when you need to do something
            // like a U2U exchange, renew, or get a referral to another realm. Realm referral isn't supported yet.

            // 1. Get the ApReq (TGT) from the PA-Data of the request
            // 2. Decrypt the TGT and extract the client calling identity
            // 3. Find the requested service principal
            // 4. Evaluate whether the client identity should get a ticket to the service
            // 5. Evaluate whether it should do U2U and if so extract that key instead
            // 6. Generate a service ticket for the calling client to the service
            // 7. return to client

            var tgsReq = (KrbTgsReq)message;

            var apReq = ExtractApReq(tgsReq);

            var krbtgtIdentity = await RealmService.Principals.RetrieveKrbtgt();

            var krbtgtKey = await krbtgtIdentity.RetrieveLongTermCredential();

            var krbtgtApReqDecrypted = DecryptApReq(apReq, krbtgtKey);

            var principal = await RealmService.Principals.Find(krbtgtApReqDecrypted.Ticket.CName.FullyQualifiedName);

            var servicePrincipal = await RealmService.Principals.Find(tgsReq.Body.SName.FullyQualifiedName);

            // renewal is an odd case here because the SName will be krbtgt
            // does this need to be validated more than the Decrypt call?

            await EvaluateSecurityPolicy(principal, servicePrincipal, krbtgtApReqDecrypted);

            KerberosKey serviceKey;

            if (tgsReq.Body.KdcOptions.HasFlag(KdcOptions.EncTktInSkey))
            {
                serviceKey = GetUserToUserTicketKey(tgsReq.Body.AdditionalTickets, krbtgtKey);
            }
            else
            {
                serviceKey = await servicePrincipal.RetrieveLongTermCredential();
            }

            var now = RealmService.Now();

            var tgsRep = await KrbKdcRep.GenerateServiceTicket <KrbTgsRep>(
                new ServiceTicketRequest
            {
                Principal           = principal,
                EncryptedPartKey    = krbtgtApReqDecrypted.SessionKey,
                ServicePrincipal    = servicePrincipal,
                ServicePrincipalKey = serviceKey,
                RealmName           = RealmService.Name,
                Addresses           = tgsReq.Body.Addresses,
                RenewTill           = krbtgtApReqDecrypted.Ticket.RenewTill,
                StartTime           = now - RealmService.Settings.MaximumSkew,
                EndTime             = now + RealmService.Settings.SessionLifetime,
                Flags = KrbKdcRep.DefaultFlags,
                Now   = now
            }
                );

            return(tgsRep.EncodeApplication());
        }