servicestack - Auth Service Saying Not Authenticated when using Permanent Sessions -
when using temporary sessions works fine. log auth service , calling /auth without parameters , shows display name, session id, etc.
when log in rememberme=true, call returns session information properly. on subsequent calls /auth without parameters, servicestack returns 401 not authenticated. session object's isauthenticated property true , exists. code checks , if it's false, forwards user login page doesn't happen know user authenticated.
i not doing different. how can authenticate permanent session , subsequent calls /auth acknowledge logged in?
if helps i'm using customcredentialsprovider.
update:
apphost code:
public override void configure(funq.container container) { //set json web services return idiomatic json camelcase properties servicestack.text.jsconfig.emitcamelcasenames = true; config.restrictallcookiestodomain = configurationmanager.appsettings["cookiedomain"]; plugins.add(new authfeature(() => new customusersession(), new iauthprovider[] { new customcredentialsprovider() { sessionexpiry = timespan.fromminutes(convert.todouble(configurationmanager.appsettings["sessiontimeout"])) }, }) //end iauthprovider { includeassignroleservices = false, includeregistrationservice = false, htmlredirect = configurationmanager.appsettings["mainsitelink"] + "login.aspx" } //end authfeature initializers );//end plugins.add authfeature plugins.add(new postmanfeature() { enablesessionexport = true });// when want feature , it's not in debugmode plugins.add(new swaggerfeature()); plugins.add(new corsfeature(allowedorigins: "*", allowedmethods: "get, post, put, delete, options", allowedheaders: "content-type, authorization, accept", allowcredentials: true)); container.register<iredisclientsmanager> (c => new pooledredisclientmanager(2, configurationmanager.appsettings["redisipport"])); container.register<icacheclient>(c => c.resolve<iredisclientsmanager>().getcacheclient()); container.register<isessionfactory>(c => new sessionfactory(c.resolve<icacheclient>())); var userrep = new inmemoryauthrepository(); container.register<iuserauthrepository>(userrep); //set mvc use same funq ioc servicestack controllerbuilder.current.setcontrollerfactory(new funqcontrollerfactory(container)); #if debug config.debugmode = true; typeof(authenticate).addattributes ( new restrictattribute (requestattributes.httpget | requestattributes.httppost) ); #else typeof(authenticate).addattributes(new restrictattribute(requestattributes.httppost)); #endif registertypedrequestfilter<authenticate>((req, res, dto) => { if (dto.username != null && dto.username != string.empty && dto.password != null && dto.password != string.empty) if(dto.rememberme == null) dto.rememberme = false; }); registertypedresponsefilter<authenticateresponse>((req, res, dto) => { var appsettings = new servicestack.configuration.appsettings(); dto.userid = apphostbase.instance.tryresolve<icacheclient>().sessionas<customusersession>().userid.tostring(); dto.meta = new dictionary<string, string>(); dto.meta.add("expiresminutes", appsettings.get("sessiontimeout")); }); } public static void start() { licensing.registerlicense(licencekey); new servicestackapphost().init(); }
initial request headers:
https://****.com/api2/auth?username=user&password=passwordmberme=true
- get /api2/auth?username=user&password=password&rememberme=true http/1.1
- accept: text/html, application/xhtml+xml, /
- accept-language: en-us
- user-agent: mozilla/5.0 (windows nt 6.1; wow64; trident/7.0; rv:11.0) gecko
- accept-encoding: gzip, deflate
- host: propel.zola360.com
- dnt: 1
- connection: keep-alive
- cookie: ss-pid=p2hslabcmss7pomrqnz5; ss-opt=perm; x-uaid=
initial response headers:
- http/1.1 200 ok
- cache-control: private
- content-type: text/html
- content-encoding: gzip
- vary: accept-encoding
- server: microsoft-iis/7.5
- x-powered-by: servicestack/4.033 win32nt/.net
- access-control-allow-origin: *
- access-control-allow-methods: get, post, put, delete, options
- access-control-allow-headers: content-type, authorization, accept
- access-control-allow-credentials: true
- x-aspnet-version: 4.0.30319
- set-cookie: ss-id=pojzknadmcecacdrecrm; domain=.zola360.com; path=/; httponly
- set-cookie: ss-opt=perm; domain=.zola360.com; expires=mon, 13-nov-2034 16:11:09 gmt; - path=/; httponly
- set-cookie: x-uaid=; domain=.zola360.com; expires=mon, 13-nov-2034 16:11:09 gmt; path=/; httponly
- set-cookie: 47=0; domain=.zola360.com; path=/
- set-cookie: userid=47; domain=.zola360.com; path=/
- x-powered-by: asp.net
- date: thu, 13 nov 2014 16:11:09 gmt
- content-length: 4129
initial response body:
{"userid":"47","sessionid":"pkritmrawxatnaabcdgn","username":"user","responsestatus":{},"meta":{"expiresminutes":"360"}}
subsequent call /auth request:
- get /api2/auth http/1.1
- accept: text/html, application/xhtml+xml, /
- accept-language: en-us
- user-agent: mozilla/5.0 (windows nt 6.1; wow64; trident/7.0; rv:11.0) gecko
- accept-encoding: gzip, deflate
- host: propel.zola360.com
- dnt: 1
- connection: keep-alive
- cookie: ss-pid=cvgslabcmss6pomydlu0; ss-opt=perm; x-uaid=; ss-id=lywzkfadmczcabcdcrm; 47=0; userid=47
subsequent call /auth response
- http/1.1 401 not authenticated
- cache-control: private
- content-type: text/html
- vary: accept
- server: microsoft-iis/7.5
- x-powered-by: servicestack/4.033 win32nt/.net
- access-control-allow-origin: *
- access-control-allow-methods: get, post, put, delete, options
- access-control-allow-headers: content-type, authorization, accept
- access-control-allow-credentials: true
- x-aspnet-version: 4.0.30319
- x-powered-by: asp.net
- date: thu, 13 nov 2014 16:11:23 gmt
- content-length: 9731
subsequent call /auth body:
{"responsestatus":{"errorcode":"not authenticated","message":"not authenticated","stacktrace":"[authenticate: 11/13/2014 3:27:49 pm]:\n[request: {}]\nservicestack.httperror: not authenticated\r\n @ servicestack.auth.authenticateservice.post(authenticate request)\r\n @ lambda_method(closure , object , object )\r\n @ servicestack.host.servicerunner`1.execute(irequest request, object instance, trequest requestdto)","errors":[]}}
update crafted small python3 script authenticate myself , call other web service. after authentication using rememberme=true, cookies come expected: ss-id/pid set fine , ss-opt=perm. figured print header cookie , paste header of request call different service marked [authenticate]. didn't work. tried silly , pasted ss-pid cookie value ss-id one. worked.
here's failing cookie string (session redacted :)):
cookie = "ss-id=ss-id-session-cookie; domain=.zola360.com; path=/; httponly, ss- pid=ss-pid-session-cookie; domain=.zola360.com; expires=tue, 14-nov-2034 01:34:25 gmt; path=/; httponly, ss-opt=perm; domain=.zola360.com; expires=tue, 14-nov-2034 01:34:25 gmt; path=/; httponly, x-uaid=; domain=.zola360.com; expires=tue, 14-nov-2034 01:34:25 gmt; path=/; httponly, 47=0; domain=.zola360.com; path=/, userid=47; domain=.zola360.com; path=/"
and pasting ss-pid value ss-id works:
cookie = "ss-id=ss-pid-session-cookie; domain=.zola360.com; path=/; httponly, ss- pid=ss-pid-session-cookie; domain=.zola360.com; expires=tue, 14-nov-2034 01:34:25 gmt; path=/; httponly, ss-opt=perm; domain=.zola360.com; expires=tue, 14-nov-2034 01:34:25 gmt; path=/; httponly, x-uaid=; domain=.zola360.com; expires=tue, 14-nov-2034 01:34:25 gmt; path=/; httponly, 47=0; domain=.zola360.com; path=/, userid=47; domain=.zola360.com; path=/"
and python3 script used:
import httplib2 http import json try: urlparse import urlparse except importerror: urllib.parse import urlparse headers = { 'accept': 'application/json', 'content-type': 'application/json; charset=utf-8' } uri = 'https://mysite.com' path = '/api2/auth/credentials' target = urlparse(uri+path) method = 'post' body = '{"username": "username", "password": "password", "rememberme": "true"}'.encode() h = http.http() response, content = h.request(target.geturl(), method, body, headers) #save cookie , use subsequent requests cookie = response['set-cookie'] print(cookie) path2 = '/api2/time/start' target2 = urlparse(uri+path2) headers['cookie'] = cookie response, content = h.request(target2.geturl(), 'get', body, headers) # assume content json reply # parse content json module data = json.loads(content.decode()) print(data)
it seems still looks @ value of ss-id if ss-opt=perm.
when authenticating get /api2/auth?username=user&password=...
sent permanent cookie ss-pid
, i.e:
cookie: ss-pid=p2hslabcmss7pomrqnz5; ss-opt=perm; x-uaid=
the rememberme=true
option tells servicestack maintain users session against permanent ss-pid
cookie. option maintained in users ss-opt=perm
cookie, http response tells client add with:
set-cookie: ss-opt=perm; domain=.zola360.com; expires=mon, 13-nov-2034 16:11:09 gmt; - path=/; httponly
although not important in case, since temporary session ss-id
missing request, servicestack tells client add new 1 with:
set-cookie: ss-id=pojzknadmcecacdrecrm; domain=.zola360.com; path=/; httponly
the issue subsequent request get /api2/auth
client not re-sending ss-pid
cookie authenticated (i.e. p2hslabcmss7pomrqnz5
vs cvgslabcmss6pomydlu0
):
cookie: ss-pid=cvgslabcmss6pomydlu0; ss-opt=perm; x-uaid=; ss-id=lywzkfadmczcabcdcrm; 47=0; userid=47
which servicestack doesn't know (i.e. doesn't maintain session against) why returns 401 not authenticated
expected.
http client should configured resend cookies
it's not clear http client you're using should configured re-send cookies default behavior. ajax send both permanent ss-pid
cookies , temporary ss-id
browser session, e.g. temporary ss-id
cookie discarded when browser closed , making new request receive new ss-id
cookie.
with c# service clients, resends permanent cookies client needs authenticated rememberme = true
, e.g:
var client = jsonserviceclient(baseurl); var authresponse = client.send(new authenticate { provider = "credentials", username = "user", password = "p@55word", rememberme = true, }); authresponse.printdump();
once authenticated same authenticated client
instance can used access protected record multiple times as seen in auth test:
for (int = 0; < 500; i++) { var response = client.send<secureresponse>(new secured { name = "test" }); console.writeline("loop : {0}", i); }
Comments
Post a Comment