Beispiel #1
0
        private async Task <SamlMessage> SamlMessageFromRequest()
        {
            var samlMessage = new SamlMessage(null, Context, Options.Configuration);

            // assumption: if the ContentType is "application/x-www-form-urlencoded" it should be safe to read as it is small.
            if (string.Equals(Request.Method, "POST", StringComparison.OrdinalIgnoreCase) &&
                !string.IsNullOrWhiteSpace(Request.ContentType)
                // May have media/type; charset=utf-8, allow partial match.
                && Request.ContentType.StartsWith("application/x-www-form-urlencoded", StringComparison.OrdinalIgnoreCase) &&
                Request.Body.CanRead)
            {
                if (!Request.Body.CanSeek)
                {
                    _logger.WriteVerbose("Buffering request body");
                    // Buffer in case this body was not meant for us.
                    MemoryStream memoryStream = new MemoryStream();
                    await Request.Body.CopyToAsync(memoryStream);

                    memoryStream.Seek(0, SeekOrigin.Begin);
                    Request.Body = memoryStream;
                }
                var form = await Request.ReadFormAsync();

                Request.Body.Seek(0, SeekOrigin.Begin);

                // TODO: a delegate on SamlAuthenticationOptions would allow for users to hook their own custom message.
                samlMessage = new SamlMessage(form, Context, Options.Configuration);
            }

            return(samlMessage);
        }
Beispiel #2
0
        /// <summary>
        /// Handles Challenge
        /// </summary>
        /// <returns></returns>
        protected override async Task ApplyResponseChallengeAsync()
        {
            if (Response.StatusCode != 401)
            {
                return;
            }

            AuthenticationResponseChallenge challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode);

            if (challenge == null)
            {
                return;
            }

            string baseUri =
                Request.Scheme +
                Uri.SchemeDelimiter +
                Request.Host +
                Request.PathBase;

            string currentUri =
                baseUri +
                Request.Path +
                Request.QueryString;

            // Save the original challenge URI so we can redirect back to it when we're done.
            AuthenticationProperties properties = challenge.Properties;

            if (string.IsNullOrEmpty(properties.RedirectUri))
            {
                properties.RedirectUri = !string.IsNullOrWhiteSpace(Options.RedirectAfterLogin) ? Options.RedirectAfterLogin : currentUri;

                if (_logger.IsEnabled(TraceEventType.Verbose))
                {
                    _logger.WriteVerbose(string.Format("Setting the RedirectUri to {0}.", properties.RedirectUri));
                }
            }

            SamlMessage samlMessage = await SamlMessageFromRequest();

            var notification = new RedirectToIdentityProviderNotification <SamlMessage, SamlAuthenticationOptions>(Context, Options)
            {
                ProtocolMessage = samlMessage
            };
            await Options.Notifications.RedirectToIdentityProvider(notification);

            if (!notification.HandledResponse)
            {
                string redirectUri = notification.ProtocolMessage.BuildRedirectUrl();
                if (!Uri.IsWellFormedUriString(redirectUri, UriKind.Absolute))
                {
                    _logger.WriteWarning("The sign-in redirect URI is malformed: " + redirectUri);
                }
                Response.Redirect(redirectUri);
            }
        }
        /// <summary>
        /// Handles Signout
        /// </summary>
        /// <returns></returns>
        protected override async Task ApplyResponseGrantAsync()
        {
            AuthenticationResponseRevoke signout = Helper.LookupSignOut(Options.AuthenticationType, Options.AuthenticationMode);

            if (signout == null)
            {
                return;
            }

            SamlMessage SamlMessage = await SamlMessageFromRequest();

            // WS Fed was "TokenAddress". Not sure this is the right endpoint
            SamlMessage.IssuerAddress = Options.Configuration.ServiceProvider.Endpoints.DefaultLogoutEndpoint.RedirectUrl ?? string.Empty;
            SamlMessage.Reply         = string.Empty;

            // Set Wreply in order:
            // 1. properties.Redirect
            // 2. Options.SignOutWreply
            // 3. Options.Wreply
            AuthenticationProperties properties = signout.Properties;

            if (properties != null && !string.IsNullOrEmpty(properties.RedirectUri))
            {
                SamlMessage.Reply = properties.RedirectUri;
            }
            else if (!string.IsNullOrWhiteSpace(Options.Configuration.ServiceProvider.Endpoints.DefaultLogoutEndpoint.RedirectUrl))
            {
                SamlMessage.Reply = Options.Configuration.ServiceProvider.Endpoints.DefaultLogoutEndpoint.RedirectUrl;
            }

            var notification = new RedirectToIdentityProviderNotification <SamlMessage, SamlAuthenticationOptions>(Context, Options)
            {
                ProtocolMessage = SamlMessage
            };
            await Options.Notifications.RedirectToIdentityProvider(notification);

            if (!notification.HandledResponse)
            {
                string redirectUri = notification.ProtocolMessage.BuildSignOutRedirectUrl();
                if (!Uri.IsWellFormedUriString(redirectUri, UriKind.Absolute))
                {
                    _logger.WriteWarning("The sign-out redirect URI is malformed: " + redirectUri);
                }

                if (Context.Request.IsAjaxRequest())
                {
                    Response.Headers.Add("X-Location", new[] { redirectUri });
                }
                else
                {
                    Response.Redirect(redirectUri);
                }
            }
        }
Beispiel #4
0
        /// <summary>
        /// Handles Challenge
        /// </summary>
        /// <returns></returns>
        protected override async Task ApplyResponseChallengeAsync()
        {
            if (Response.StatusCode != 401)
            {
                return;
            }

            AuthenticationResponseChallenge challenge = Helper.LookupChallenge(Options.AuthenticationType, Options.AuthenticationMode);

            if (challenge == null)
            {
                return;
            }

            string baseUri =
                Request.Scheme +
                Uri.SchemeDelimiter +
                Request.Host +
                Request.PathBase;

            string currentUri =
                baseUri +
                Request.Path +
                Request.QueryString;

            // Save the original challenge URI so we can redirect back to it when we're done.
            AuthenticationProperties properties = challenge.Properties;

            if (string.IsNullOrEmpty(properties.RedirectUri))
            {
                properties.RedirectUri = currentUri;
            }

            SamlMessage SamlMessage = await SamlMessageFromRequest();

            {
                //IssuerAddress = _configuration.TokenEndpoint ?? string.Empty,
                //Wtrealm = Options.Wtrealm,
                //Wctx = SamlAuthenticationDefaults.WctxKey + "=" + Uri.EscapeDataString(Options.StateDataFormat.Protect(properties)),
                //Wa = SamlActions.SignIn,
            };

            //if (!string.IsNullOrWhiteSpace(Options.Wreply))
            //{
            //    SamlMessage.Wreply = Options.Wreply;
            //}

            var notification = new RedirectToIdentityProviderNotification <SamlMessage, SamlAuthenticationOptions>(Context, Options)
            {
                ProtocolMessage = SamlMessage
            };
            await Options.Notifications.RedirectToIdentityProvider(notification);

            if (!notification.HandledResponse)
            {
                string redirectUri = notification.ProtocolMessage.BuildRedirectUrl();
                if (!Uri.IsWellFormedUriString(redirectUri, UriKind.Absolute))
                {
                    _logger.WriteWarning("The sign-in redirect URI is malformed: " + redirectUri);
                }
                Response.Redirect(redirectUri);
            }
        }
Beispiel #5
0
        /// <summary>
        /// Invokes the login procedure (2nd leg of SP-Initiated login). Analagous to Saml20SignonHandler from ASP.Net DLL
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task <AuthenticationTicket> Invoke(IOwinContext context)
        {
            Logger.Debug(TraceMessages.SignOnHandlerCalled);
            ExceptionDispatchInfo authFailedEx = null;

            try {
                var messageReceivedNotification = new MessageReceivedNotification <SamlMessage, SamlAuthenticationOptions>(context, options)
                {
                    ProtocolMessage = new SamlMessage(context, configuration, null)
                };
                await options.Notifications.MessageReceived(messageReceivedNotification);

                if (messageReceivedNotification.HandledResponse)
                {
                    return(null); // GetHandledResponseTicket()
                }
                if (messageReceivedNotification.Skipped)
                {
                    return(null);
                }
                var requestParams = await HandleResponse(context);

                var assertion = context.Get <Saml20Assertion>("Saml2:assertion");
                var securityTokenReceivedNotification = new SecurityTokenReceivedNotification <SamlMessage, SamlAuthenticationOptions>(context, options)
                {
                    ProtocolMessage = new SamlMessage(context, configuration, assertion)
                };
                await options.Notifications.SecurityTokenReceived(securityTokenReceivedNotification);

                if (securityTokenReceivedNotification.HandledResponse)
                {
                    return(null); // GetHandledResponseTicket();
                }
                if (securityTokenReceivedNotification.Skipped)
                {
                    return(null);
                }

                var ticket = await GetAuthenticationTicket(context, requestParams);

                var securityTokenValidatedNotification = new SecurityTokenValidatedNotification <SamlMessage, SamlAuthenticationOptions>(context, options)
                {
                    AuthenticationTicket = ticket,
                    ProtocolMessage      = new SamlMessage(context, configuration, assertion)
                };

                await options.Notifications.SecurityTokenValidated(securityTokenValidatedNotification);

                if (securityTokenValidatedNotification.HandledResponse)
                {
                    return(null); // GetHandledResponseTicket();
                }
                if (securityTokenValidatedNotification.Skipped)
                {
                    return(null); // null;
                }
                // Flow possible changes
                ticket = securityTokenValidatedNotification.AuthenticationTicket;
                context.Authentication.AuthenticationResponseGrant = new AuthenticationResponseGrant(ticket.Identity, ticket.Properties);
                return(ticket);
            }
            catch (Exception ex) {
                var endpointException = new SamlEndpointException("Error during login request, see inner exception", ex);
                authFailedEx = ExceptionDispatchInfo.Capture(endpointException);
            }
            if (authFailedEx != null)
            {
                Logger.Error("Exception occurred while processing message: " + authFailedEx.SourceException);
                var message = new SamlMessage(context, configuration, context.Get <Saml20Assertion>("Saml2:assertion"));
                var authenticationFailedNotification = new AuthenticationFailedNotification <SamlMessage, SamlAuthenticationOptions>(context, options)
                {
                    ProtocolMessage = message,
                    Exception       = authFailedEx.SourceException
                };
                await options.Notifications.AuthenticationFailed(authenticationFailedNotification);

                if (authenticationFailedNotification.HandledResponse)
                {
                    return(null);//GetHandledResponseTicket();
                }
                if (authenticationFailedNotification.Skipped)
                {
                    return(null); //null
                }
                authFailedEx.Throw();
            }
            return(null);
        }
Beispiel #6
0
        /// <summary>
        /// Invokes the login procedure (2nd leg of SP-Initiated login). Analagous to Saml20SignonHandler from ASP.Net DLL
        /// </summary>
        /// <param name="context"></param>
        /// <returns></returns>
        public async Task<AuthenticationTicket> Invoke(IOwinContext context)
        {
            Logger.Debug(TraceMessages.SignOnHandlerCalled);
            ExceptionDispatchInfo authFailedEx = null;
            try {
                var messageReceivedNotification = new MessageReceivedNotification<SamlMessage, SamlAuthenticationOptions>(context, options)
                {
                    ProtocolMessage = new SamlMessage(context, configuration, null)
                };
                await options.Notifications.MessageReceived(messageReceivedNotification);
                if (messageReceivedNotification.HandledResponse) {
                    return null; // GetHandledResponseTicket()
                }
                if (messageReceivedNotification.Skipped) {
                    return null;
                }
                var requestParams = await HandleResponse(context);
                var assertion = context.Get<Saml20Assertion>("Saml2:assertion");
                var securityTokenReceivedNotification = new SecurityTokenReceivedNotification<SamlMessage, SamlAuthenticationOptions>(context, options)
                {
                    ProtocolMessage = new SamlMessage(context, configuration, assertion)
                };
                await options.Notifications.SecurityTokenReceived(securityTokenReceivedNotification);
                if (securityTokenReceivedNotification.HandledResponse) {
                    return null; // GetHandledResponseTicket();
                }
                if (securityTokenReceivedNotification.Skipped) {
                    return null;
                }

                var ticket = await GetAuthenticationTicket(context, requestParams);

                var securityTokenValidatedNotification = new SecurityTokenValidatedNotification<SamlMessage, SamlAuthenticationOptions>(context, options)
                {
                    AuthenticationTicket = ticket,
                    ProtocolMessage = new SamlMessage(context, configuration, assertion)
                };

                await options.Notifications.SecurityTokenValidated(securityTokenValidatedNotification);
                if (securityTokenValidatedNotification.HandledResponse) {
                    return null; // GetHandledResponseTicket();
                }
                if (securityTokenValidatedNotification.Skipped) {
                    return null; // null;
                }
                // Flow possible changes
                ticket = securityTokenValidatedNotification.AuthenticationTicket;

                context.Authentication.AuthenticationResponseGrant = new AuthenticationResponseGrant(ticket.Identity, ticket.Properties);                
                return ticket;
            }
            catch (Exception ex) {
                authFailedEx = ExceptionDispatchInfo.Capture(ex);
            }
            if (authFailedEx != null) {
                Logger.Error("Exception occurred while processing message: " + authFailedEx.SourceException);
                var message = new SamlMessage(context, configuration, context.Get<Saml20Assertion>("Saml2:assertion"));
                var authenticationFailedNotification = new AuthenticationFailedNotification<SamlMessage, SamlAuthenticationOptions>(context, options)
                {
                    ProtocolMessage = message,
                    Exception = authFailedEx.SourceException
                };
                await options.Notifications.AuthenticationFailed(authenticationFailedNotification);
                if (authenticationFailedNotification.HandledResponse) {
                    return null;//GetHandledResponseTicket();
                }
                if (authenticationFailedNotification.Skipped) {
                    return null; //null
                }

                authFailedEx.Throw();
            }
            return null;
        }