Exemplo n.º 1
0
        /// <summary>
        /// Validates a ticket contained in the URL, presumably generated by
        /// the CAS server after a successful authentication.  The actual ticket
        /// validation is performed by the configured TicketValidator
        /// (i.e., CAS 1.0, CAS 2.0, SAML 1.0).  If the validation succeeds, the
        /// request is authenticated and a FormsAuthenticationCookie and
        /// corresponding CasAuthenticationTicket are created for the purpose of
        /// authenticating subsequent requests (see ProcessTicketValidation
        /// method).  If the validation fails, the authentication status remains
        /// unchanged (generally the user is and remains anonymous).
        /// </summary>
        public void ProcessTicketValidation(HttpContextBase httpContext)
        {
            HttpApplication app     = httpContext.ApplicationInstance;
            HttpRequestBase request = httpContext.Request;

            string ticket = request[_casServices.Settings.ArtifactParameterName];

            try {
                // Attempt to authenticate the ticket and resolve to an ICasPrincipal
                var principal = TicketValidator.Validate(ticket);

                // Save the ticket in the FormsAuthTicket.  Encrypt the ticket and send it as a cookie.
                var casTicket = new CasAuthenticationTicket(
                    ticket,
                    _urlUtil.RemoveCasArtifactsFromUrl(request.Url.AbsoluteUri),
                    request.UserHostAddress,
                    principal.Assertion,
                    principal.MaxAttributes,
                    _clock.UtcNow
                    );

                if (_casServices.ProxyTicketManager != null && !string.IsNullOrEmpty(principal.ProxyGrantingTicket))
                {
                    casTicket.ProxyGrantingTicketIou = principal.ProxyGrantingTicket;
                    casTicket.Proxies.AddRange(principal.Proxies);
                    string proxyGrantingTicket = _casServices.ProxyTicketManager.GetProxyGrantingTicket(casTicket.ProxyGrantingTicketIou);
                    if (!string.IsNullOrEmpty(proxyGrantingTicket))
                    {
                        casTicket.ProxyGrantingTicket = proxyGrantingTicket;
                    }
                }

                // TODO: Check the last 2 parameters.  We want to take the from/to dates from the FormsAuthenticationTicket.
                // However, we may need to do some clock drift correction.
                FormsAuthenticationTicket formsAuthTicket = CreateFormsAuthenticationTicket(
                    principal.Identity.Name,
                    ticket,
                    null,
                    null);

                SetAuthCookie(httpContext, formsAuthTicket);

                // Also save the ticket in the server store (if configured)
                if (_casServices.ServiceTicketManager != null)
                {
                    _casServices.ServiceTicketManager.UpdateTicketExpiration(casTicket, formsAuthTicket.Expiration);
                }

                // Jump directly to EndRequest.  Don't allow the Page and/or Handler to execute.
                // EndRequest will redirect back without the ticket in the URL
                app.CompleteRequest();
                return;
            }
            catch (TicketValidationException e) {
                // Leave principal null.  This might not have been a CAS service ticket.
                Logger.Error(e, "Ticket validation error: {0}", e);
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Attempts to authenticate requests subsequent to the initial authentication
        /// request (handled by ProcessTicketValidation).  This method looks for a
        /// FormsAuthenticationCookie containing a FormsAuthenticationTicket and attempts
        /// to confirms its validitiy.  It either contains the CAS service ticket or a
        /// reference to a CasAuthenticationTicket stored in the ServiceTicketManager
        /// (if configured).  If it succeeds, the context.User and Thread.CurrentPrincipal
        /// are set with a ICasPrincipal and the current request is considered
        /// authenticated.  Otherwise, the current request is effectively anonymous.
        /// </summary>
        public void ProcessRequestAuthentication(HttpContextBase httpContext)
        {
            // Look for a valid FormsAuthenticationTicket encrypted in a cookie.
            CasAuthenticationTicket   casTicket = null;
            FormsAuthenticationTicket formsAuthenticationTicket = GetFormsAuthenticationTicket(httpContext);

            if (formsAuthenticationTicket != null)
            {
                ICasPrincipal principal;
                if (_casServices.ServiceTicketManager != null)
                {
                    string serviceTicket = formsAuthenticationTicket.UserData;
                    casTicket = _casServices.ServiceTicketManager.GetTicket(serviceTicket);
                    if (casTicket != null)
                    {
                        IAssertion assertion = casTicket.Assertion;

                        if (!_casServices.ServiceTicketManager.VerifyClientTicket(casTicket))
                        {
                            Logger.Warning("CasAuthenticationTicket failed verification: {0}", casTicket);

                            // Deletes the invalid FormsAuthentication cookie from the client.
                            ClearAuthCookie(httpContext);
                            _casServices.ServiceTicketManager.RevokeTicket(serviceTicket);

                            // Don't give this request a User/Principal.  Remove it if it was created
                            // by the underlying FormsAuthenticationModule or another module.
                            principal = null;
                        }
                        else
                        {
                            if (_casServices.ProxyTicketManager != null &&
                                !string.IsNullOrEmpty(casTicket.ProxyGrantingTicketIou) &&
                                string.IsNullOrEmpty(casTicket.ProxyGrantingTicket))
                            {
                                string proxyGrantingTicket = _casServices.ProxyTicketManager.GetProxyGrantingTicket(casTicket.ProxyGrantingTicketIou);
                                if (!string.IsNullOrEmpty(proxyGrantingTicket))
                                {
                                    casTicket.ProxyGrantingTicket = proxyGrantingTicket;
                                }
                            }

                            principal = new CasPrincipal(assertion, casTicket.ProxyGrantingTicket, null, casTicket.MaxAttributes);
                        }
                    }
                    else
                    {
                        if (httpContext.User != null &&
                            httpContext.User.Identity is FormsIdentity &&
                            _authenticationService.GetAuthenticatedUser() != null)
                        {
                            return;
                        }

                        // This didn't resolve to a ticket in the TicketStore.  Revoke it.
                        ClearAuthCookie(httpContext);
                        Logger.Debug("Revoking ticket {0}", serviceTicket);
                        _casServices.ServiceTicketManager.RevokeTicket(serviceTicket);

                        // Don't give this request a User/Principal.  Remove it if it was created
                        // by the underlying FormsAuthenticationModule or another module.
                        principal = null;
                    }
                }
                else
                {
                    principal = new CasPrincipal(new Assertion(formsAuthenticationTicket.Name));
                }

                httpContext.User        = principal;
                Thread.CurrentPrincipal = principal;

                if (principal == null)
                {
                    // Remove the cookie from the client
                    ClearAuthCookie(httpContext);
                }
                else
                {
                    // Extend the expiration of the cookie if FormsAuthentication is configured to do so.
                    if (FormsAuthentication.SlidingExpiration)
                    {
                        FormsAuthenticationTicket newTicket = FormsAuthentication.RenewTicketIfOld(formsAuthenticationTicket);
                        if (newTicket != null && newTicket != formsAuthenticationTicket)
                        {
                            SetAuthCookie(httpContext, newTicket);
                            if (_casServices.ServiceTicketManager != null)
                            {
                                _casServices.ServiceTicketManager.UpdateTicketExpiration(casTicket, newTicket.Expiration);
                            }
                        }
                    }
                }
            }
        }
Exemplo n.º 3
0
        /// <summary>
        /// Attempts to connect to the CAS server to retrieve a proxy ticket
        /// for the target URL specified.
        /// </summary>
        /// <remarks>
        /// Problems retrieving proxy tickets are generally caused by SSL misconfiguration.
        /// The CAS server must be configured to trust the SSL certificate on the web application's
        /// server.  The CAS server will attempt to establish an SSL connection to this web
        /// application server to confirm that the proxy ticket request is legitimate.  If the
        /// server does not trust the SSL certificate or the certificate authority/chain of the SSL
        /// certificate, the request will fail.
        /// </remarks>
        /// <param name="httpContext"></param>
        /// <param name="targetServiceUrl">The target Url to obtain a proxy ticket for</param>
        /// <returns>
        /// A proxy ticket for the target Url or an empty string if the request failed.
        /// </returns>
        public string GetProxyTicketIdFor(HttpContextBase httpContext, string targetServiceUrl)
        {
            Argument.ThrowIfNullOrEmpty(targetServiceUrl, "targetServiceUrl", "targetServiceUrl parameter cannot be null or empty.");

            if (_casServices.ServiceTicketManager == null)
            {
                LogAndThrowConfigurationException("Proxy authentication requires a ServiceTicketManager");
            }

            FormsAuthenticationTicket formsAuthTicket = GetFormsAuthenticationTicket(httpContext);

            if (formsAuthTicket == null)
            {
                LogAndThrowOperationException("The request is not authenticated (does not have a CAS Service or Proxy ticket).");
            }

            if (string.IsNullOrEmpty(formsAuthTicket.UserData))
            {
                LogAndThrowOperationException("The request does not have a CAS Service Ticket.");
            }

            CasAuthenticationTicket casTicket = _casServices.ServiceTicketManager.GetTicket(formsAuthTicket.UserData);

            if (casTicket == null)
            {
                LogAndThrowOperationException("The request does not have a valid CAS Service Ticket.");
            }

            string proxyTicketResponse = null;

            try {
                string proxyUrl = _urlUtil.ConstructProxyTicketRequestUrl(casTicket.ProxyGrantingTicket, targetServiceUrl);
                proxyTicketResponse = HttpUtil.PerformHttpGet(proxyUrl, true);
            }
            catch {
                LogAndThrowOperationException("Unable to obtain CAS Proxy Ticket.");
            }

            if (String.IsNullOrEmpty(proxyTicketResponse))
            {
                LogAndThrowOperationException("Unable to obtain CAS Proxy Ticket (response was empty)");
            }

            string proxyTicket = null;

            try {
                ServiceResponse serviceResponse = ServiceResponse.ParseResponse(proxyTicketResponse);
                if (serviceResponse.IsProxySuccess)
                {
                    ProxySuccess success = (ProxySuccess)serviceResponse.Item;
                    if (!String.IsNullOrEmpty(success.ProxyTicket))
                    {
                        Logger.Information("Proxy success: {0}", success.ProxyTicket);
                    }
                    proxyTicket = success.ProxyTicket;
                }
                else
                {
                    ProxyFailure failure = (ProxyFailure)serviceResponse.Item;
                    if (!String.IsNullOrEmpty(failure.Message) && !String.IsNullOrEmpty(failure.Code))
                    {
                        Logger.Information("Proxy failure: {0} ({1})", failure.Message, failure.Code);
                    }
                    else if (!String.IsNullOrEmpty(failure.Message))
                    {
                        Logger.Information("Proxy failure: {0}", failure.Message);
                    }
                    else if (!String.IsNullOrEmpty(failure.Code))
                    {
                        Logger.Information("Proxy failure: Code {0}", failure.Code);
                    }
                }
            }
            catch (InvalidOperationException) {
                LogAndThrowOperationException("CAS Server response does not conform to CAS 2.0 schema");
            }
            return(proxyTicket);
        }
Exemplo n.º 4
0
        /// <summary>
        /// Validates a ticket contained in the URL, presumably generated by
        /// the CAS server after a successful authentication.  The actual ticket
        /// validation is performed by the configured TicketValidator 
        /// (i.e., CAS 1.0, CAS 2.0, SAML 1.0).  If the validation succeeds, the
        /// request is authenticated and a FormsAuthenticationCookie and 
        /// corresponding CasAuthenticationTicket are created for the purpose of 
        /// authenticating subsequent requests (see ProcessTicketValidation 
        /// method).  If the validation fails, the authentication status remains 
        /// unchanged (generally the user is and remains anonymous).
        /// </summary>
        public void ProcessTicketValidation(HttpContextBase httpContext) {
            HttpApplication app = httpContext.ApplicationInstance;
            HttpRequestBase request = httpContext.Request;

            string ticket = request[_casServices.Settings.ArtifactParameterName];

            try {
                // Attempt to authenticate the ticket and resolve to an ICasPrincipal
                var principal = TicketValidator.Validate(ticket);

                // Save the ticket in the FormsAuthTicket.  Encrypt the ticket and send it as a cookie. 
                var casTicket = new CasAuthenticationTicket(
                    ticket,
                    _urlUtil.RemoveCasArtifactsFromUrl(request.Url.AbsoluteUri),
                    request.UserHostAddress,
                    principal.Assertion,
                    _clock.UtcNow
                    );

                if (_casServices.ProxyTicketManager != null && !string.IsNullOrEmpty(principal.ProxyGrantingTicket)) {
                    casTicket.ProxyGrantingTicketIou = principal.ProxyGrantingTicket;
                    casTicket.Proxies.AddRange(principal.Proxies);
                    string proxyGrantingTicket = _casServices.ProxyTicketManager.GetProxyGrantingTicket(casTicket.ProxyGrantingTicketIou);
                    if (!string.IsNullOrEmpty(proxyGrantingTicket)) {
                        casTicket.ProxyGrantingTicket = proxyGrantingTicket;
                    }
                }

                // TODO: Check the last 2 parameters.  We want to take the from/to dates from the FormsAuthenticationTicket.  
                // However, we may need to do some clock drift correction.
                FormsAuthenticationTicket formsAuthTicket = CreateFormsAuthenticationTicket(
                    principal.Identity.Name,
                    ticket, 
                    null, 
                    null);

                SetAuthCookie(httpContext, formsAuthTicket);

                // Also save the ticket in the server store (if configured)
                if (_casServices.ServiceTicketManager != null) {
                    _casServices.ServiceTicketManager.UpdateTicketExpiration(casTicket, formsAuthTicket.Expiration);
                }

                // Jump directly to EndRequest.  Don't allow the Page and/or Handler to execute.
                // EndRequest will redirect back without the ticket in the URL
                app.CompleteRequest();
                return;
            }
            catch (TicketValidationException e) {
                // Leave principal null.  This might not have been a CAS service ticket.
                Logger.Error(e, "Ticket validation error: {0}", e);
            }
        }