Zoran Knezevic - 151 - Jan 30, 2014

Hi,
I have a ASP.NET Forms / MVC 5 / Service Stack application (i know, it’s a nice mix).  It uses the ASP.NET Membership.  The login page is an web forms page.  Once the user is authenticated I want to make sure that the user is also authenticated against the service stack services that are hosted under the same project.  In order to be able to reuse the asp.net membership framework I created a CustomCredentialsAuthProvider for SS.  So then my thought was that I could just call the:

var authService = AppHostBase.Instance.Resolve<AuthenticateService>();
            authService.Request = System.Web.HttpContext.Current.ToRequest();
            var response = authService.Authenticate(new Authenticate
            {
                UserName = ((Login)sender).UserName,
                Password = ((Login)sender).Password,
                RememberMe = ((Login)sender).RememberMeSet
            });  

Even though this call goes through, when I try to hit any of the SS services I get an error and the redirect url to /login.  

Am I missing something?

Here is my apphost:
//Plugins
            Plugins.Add(new RazorFormat());
            Plugins.Add(new SessionFeature());
            Plugins.Add(new AuthFeature(() => new CustomUserSession(),
                                              new IAuthProvider[] { new CustomCredentialsAuthProvider() }));            

            container.Register<ICacheClient>(new MemoryCacheClient());

Can you check on the HTTP Response if the ServiceStack ss-pid cookie is being set?

Note: you should resolve ServiceStack  services from inside a MVC Controller with:

using (var svc = HostContext.ResolveService<AuthenticateService>(base.Request.ToRequest()))
{
    //…
}

Can you try the code above to see how that goes?

Also posts with a lot of source code is easier to read on StackOverflow, you can post a link here so we can see it.

Zoran Knezevic:

This login page is a web forms page.  So I am using the PageBase class.  So I modified my code to :
using (var authService = HostContext.ResolveService<AuthenticateService>(HttpContext.Current.ToRequest()))
            {
                var response = authService.Authenticate(new Authenticate
                {
                    UserName = ((Login)sender).UserName,
                    Password = ((Login)sender).Password,
                    RememberMe = ((Login)sender).RememberMeSet
                });
            }

The code executes without errors and when I view the Cookies in the browser I have the “ss-id” and “ss-pid” cookies.  But hitting a service that has the [Authenticate] attribute shows me a message that the handler could not be found with the redirect to login.  

Btw, I will move this to stack overflow.

Zoran Knezevic:

If I remove the Authenticate attribute and get to the service I am able to pull out the custom session information that was saved in the OnAuthenticated() method in my CustomCredentialsAuthProvider.  

That’s weird, can you also post the HTTP Requests/Responses, seems odd that the cookies are passed through but it’s coming back as non-authenticated.

Wayne Brantley:

I wrote a filter provider.  Works like this:      [ServiceStackToAspNetAuthorize(Roles = “somerole”)]

Wayne Brantley:

Code looks like this.  (I sent for inclusion in SS, but Demis said he had other ‘bigger’ plans to help those of us trying to use them together and pull was rejected).  

    public class ServiceStackToAspNetAuthorizeAttribute : RequestFilterAttribute
    {
        private string _roles;
        private string[] _rolesSplit = new string[0];

        public string Roles
        {
            get { return _roles ?? String.Empty; }
            set
            {
                _roles = value;
                _rolesSplit = SplitString(value);
            }
        }

        public ServiceStackToAspNetAuthorizeAttribute(ApplyTo applyTo)
            : base(applyTo)
        {
            this.Priority = (int)RequestFilterPriority.Authenticate;
        }

        public ServiceStackToAspNetAuthorizeAttribute()
            : this(ApplyTo.All) { }


        public override void Execute(IRequest req, IResponse res, object requestDto)
        {
            if (!InternalAuthorize())
            {
                res.StatusCode = (int)HttpStatusCode.Unauthorized;
                res.EndRequest();
            }
        }

        private bool InternalAuthorize()
        {
            var context = HttpContext.Current;
            if (context != null)
            {
                var user = context.User;
                if (user != null)
                {
                    if (!user.Identity.IsAuthenticated)
                        return false;
                    if (_rolesSplit.Length > 0 && !_rolesSplit.Any(user.IsInRole))
                        return false;
                    return true;
                }
            }
            return false;
        }

        private static string[] SplitString(string original)
        {
            if (String.IsNullOrEmpty(original))
            {
                return new string[0];
            }

            var split = from piece in original.Split(’,’)
                        let trimmed = piece.Trim()
                        where !String.IsNullOrEmpty(trimmed)
                        select trimmed;
            return split.ToArray();
        }

    }

Zoran Knezevic:

Hey Demis,
So I tried to simplify my project.  I created an asp.net host using the servicestack.host.aspnet nuget package.  With a basic scenario of a SS TestService automatically authenticating the user and I got other errors.  I’m hoping that if I can get this to work that the other asp.net webforms/mvc5 project will work as well.

I tried to put as many details into this stackoverflow question.  http://stackoverflow.com/questions/21467903/servicestack-authentication-you-dont-need-to-use-ihttprequest-tryresolveihttpr

Let me know if there is anything else I need to add.

Zoran Knezevic:

+Wayne Brantley Thanks for the input.  At this point I am not trying to reuse anything from the ASP.NET Membership as we are transitioning the whole project to SS.  But in the meantime I just need to authenticate the ASP.NET and SS via that one login page.  Then over then next few years we will be moving pieces over.  What I find odd is that I was not even able to create a Test SS Service that calls the AuthenticateService and logs the user in as explained in detail in my stackoverflow link.

+Zoran Knezevic FYI, just responded on StackOverflow with a workaround, i.e. add this after calling the Auth Service:         base.Request.ResponseContentType = MimeTypes.Html;

Otherwise you can ignore it if you go with the latest release on MyGet:
https://github.com/ServiceStack/ServiceStack/wiki/MyGet

Zoran Knezevic:

+Demis Bellot Thanks for the response!  Sorry that it kept you up to 3AM.  You resolved the first part of my issue.  I have commented on the question and created another question with more details on the second part which is still not working.  You can find that here http://stackoverflow.com/questions/21482929/servicestack-authentication-authenticate-attribute-fails-to-process-the-ss-id.  Thanks for your help.

No worries, tho I’m still in Australia so it wasn’t 3am over here :). 

This is strange, as your example works for me, e.g. hitting TestService authenticated me in and let me hit a helloauth service that required authentication where it didn’t allow me before. Can you post the HTTP Request and Response headers on the question so we can see what’s going on. You should be able to use the Network tab in WebInspector or Fiddler.

Zoran Knezevic:

Gotcha.  So, it turned out that it was an error on my end.  You can see the comments on the question to see my blunder.  Thanks for your help.

Awesome, glad you worked it out! Great to have Scott around, he’s been a superstar on StackOverflow.

Zoran Knezevic:

Yes he is!
__________

Wayne Brantley:

Demis, I remember you were going to AUS, but I figured it was for a week or two…you are still there?  Awesome…are you even going to come back?  :-)

Yep, flying back this weekend coming up.