Fossil

Check-in [affdf56c]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:logout now fails if the auth token is not available to it (as a sanity check and potentially stop someone from logging out someone else).
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | json
Files: files | file ages | folders
SHA1: affdf56c3fef4e57c6a72b55e6e592d929b04eaa
User & Date: stephan 2011-09-17 14:24:24.326
Context
2011-09-17
16:01
More cleaning up of error lower-level handling to output JSON instead of HTML in a few more cases. ... (check-in: 9b842564 user: stephan tags: json)
14:24
logout now fails if the auth token is not available to it (as a sanity check and potentially stop someone from logging out someone else). ... (check-in: affdf56c user: stephan tags: json)
01:25
dropped back to a simpler timestamp generation mechanism. Thanks to Ge Weijers for the input. ... (check-in: 147f4bfb user: stephan tags: json)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/json.c.
52
53
54
55
56
57
58

59
60
61
62
63
64
65
FSL_JSON_E_RESOURCE_NOT_FOUND = FSL_JSON_E_GENERIC_SUB1 + 4,
FSL_JSON_E_TIMEOUT = FSL_JSON_E_GENERIC_SUB1 + 5,
FSL_JSON_E_ASSERT = FSL_JSON_E_GENERIC_SUB1 + 6,
FSL_JSON_E_ALLOC = FSL_JSON_E_GENERIC_SUB1 + 7,
FSL_JSON_E_NYI = FSL_JSON_E_GENERIC_SUB1 + 8,

FSL_JSON_E_AUTH = 2000,

FSL_JSON_E_MISSING_AUTH = FSL_JSON_E_AUTH + 2,
FSL_JSON_E_DENIED = FSL_JSON_E_AUTH + 3,
FSL_JSON_E_WRONG_MODE = FSL_JSON_E_AUTH + 4,

FSL_JSON_E_LOGIN_FAILED = FSL_JSON_E_AUTH + 100,
FSL_JSON_E_LOGIN_FAILED_NONAME = FSL_JSON_E_LOGIN_FAILED + 1,
FSL_JSON_E_LOGIN_FAILED_NOPW = FSL_JSON_E_LOGIN_FAILED + 2,







>







52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
FSL_JSON_E_RESOURCE_NOT_FOUND = FSL_JSON_E_GENERIC_SUB1 + 4,
FSL_JSON_E_TIMEOUT = FSL_JSON_E_GENERIC_SUB1 + 5,
FSL_JSON_E_ASSERT = FSL_JSON_E_GENERIC_SUB1 + 6,
FSL_JSON_E_ALLOC = FSL_JSON_E_GENERIC_SUB1 + 7,
FSL_JSON_E_NYI = FSL_JSON_E_GENERIC_SUB1 + 8,

FSL_JSON_E_AUTH = 2000,
/* #2001: re-use */
FSL_JSON_E_MISSING_AUTH = FSL_JSON_E_AUTH + 2,
FSL_JSON_E_DENIED = FSL_JSON_E_AUTH + 3,
FSL_JSON_E_WRONG_MODE = FSL_JSON_E_AUTH + 4,

FSL_JSON_E_LOGIN_FAILED = FSL_JSON_E_AUTH + 100,
FSL_JSON_E_LOGIN_FAILED_NONAME = FSL_JSON_E_LOGIN_FAILED + 1,
FSL_JSON_E_LOGIN_FAILED_NOPW = FSL_JSON_E_LOGIN_FAILED + 2,
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
** be cson_value_free()d or transfered to a JSON container.
*/
cson_value * json_rc_string( int code ){
  return cson_value_new_string( json_rc_cstr(code), 11 );
}

/*
** UNTESTED!!!
**
** Returns the current request's JSON authentication token, or NULL if
** none is found. The token's memory is owned by (or shared with)
** g.json.cgiCx.
**
** If an auth token is found in the GET/POST JSON request data then
** fossil is given that data for use in authentication for this
** session.







<
<







202
203
204
205
206
207
208


209
210
211
212
213
214
215
** be cson_value_free()d or transfered to a JSON container.
*/
cson_value * json_rc_string( int code ){
  return cson_value_new_string( json_rc_cstr(code), 11 );
}

/*


** Returns the current request's JSON authentication token, or NULL if
** none is found. The token's memory is owned by (or shared with)
** g.json.cgiCx.
**
** If an auth token is found in the GET/POST JSON request data then
** fossil is given that data for use in authentication for this
** session.
226
227
228
229
230
231
232
233



234
235
236
237
238

239
240



241
242
243
244
245
246
247
  if( !g.json.authToken ){
    /* Try to get an authorization token from GET parameter, POSTed
       JSON, or fossil cookie (in that order). */
    g.json.authToken = cson_cgi_getenv(&g.json.cgiCx, "gp", FossilJsonKeys.authToken)
      /* reminder to self: cson_cgi does not have access to the cookies
         because fossil's core consumes them. Thus we cannot use "agpc"
         here. We use "a" (App-specific) as a place to store fossil's
         cookie value.



      */;
    if( g.json.authToken){
      /* tell fossil to use this login info.
         
         FIXME: because the JSON bits don't carry around login_cookie_name(),

         there is a login hijacking window here. We need to change the
         JSON auth token to be in the form: login_cookie_name()=...



      */
      cgi_replace_parameter( login_cookie_name(), cson_value_get_cstr(g.json.authToken) );
    }else if( g.isCGI ){
      /* try fossil's conventional cookie. */
      /* Reminder: chicken/egg scenario regarding db access in CLI
         mode because login_cookie_name() needs the db. */
      char const * zCookie = P(login_cookie_name());







|
>
>
>

|


|
>
|
|
>
>
>







225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
  if( !g.json.authToken ){
    /* Try to get an authorization token from GET parameter, POSTed
       JSON, or fossil cookie (in that order). */
    g.json.authToken = cson_cgi_getenv(&g.json.cgiCx, "gp", FossilJsonKeys.authToken)
      /* reminder to self: cson_cgi does not have access to the cookies
         because fossil's core consumes them. Thus we cannot use "agpc"
         here. We use "a" (App-specific) as a place to store fossil's
         cookie value. Reminder #2: in server mode cson_cgi also doesn't
         have access to the GET parameters because of how the QUERY_STRING
         is set. That's on my to-fix list for cson_cgi (feeding it our own
         query string).
      */;
    if(g.json.authToken && cson_value_is_string(g.json.authToken)){
      /* tell fossil to use this login info.
         
         FIXME: because the JSON bits don't carry around
         login_cookie_name(), there is a potential login hijacking
         window here. We may need to change the JSON auth token to be
         in the form: login_cookie_name()=...

         Then again, the hardened cookie value helps ensure that
         only a proper key/value match is valid.
      */
      cgi_replace_parameter( login_cookie_name(), cson_value_get_cstr(g.json.authToken) );
    }else if( g.isCGI ){
      /* try fossil's conventional cookie. */
      /* Reminder: chicken/egg scenario regarding db access in CLI
         mode because login_cookie_name() needs the db. */
      char const * zCookie = P(login_cookie_name());
855
856
857
858
859
860
861
862
863
864
865
866















867




868
869
870
871
872
873
874
#endif
  }
}

/*
** Impl of /json/logout.
**
** Shortcomings: this never reports failure, as we don't go through
** the trouble of actually checking whether the user is logged in or
** not.
*/
cson_value * json_page_logout(void){















  login_clear_login_data();




  return NULL;
}

/*
** Implementation of the /json/stat page/command.
**
*/







<
<
<


>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
|
>
>
>
>







861
862
863
864
865
866
867



868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
#endif
  }
}

/*
** Impl of /json/logout.
**



*/
cson_value * json_page_logout(void){
  cson_value const *token = g.json.authToken;
    /* Remember that json_bootstrap() replaces the login cookie with
       the JSON auth token if the request contains it. If the reqest
       is missing the auth token then this will fetch fossil's
       original cookie. Either way, it's what we want :).

       We require the auth token to avoid someone maliciously
       trying to log someone else out (not 100% sure if that
       would be possible, given fossil's hardened cookie, but
       i'll assume it would be for the time being).
    */
    ;
  if(!token){
    g.json.resultCode = FSL_JSON_E_MISSING_AUTH;
  }else{
    login_clear_login_data();
    g.json.authToken = NULL /* memory is owned by g.json.cgiCx, but
                               now lives only in the cson_cgi garbage
                               collector.*/;
  }
  return NULL;
}

/*
** Implementation of the /json/stat page/command.
**
*/
Changes to src/login.c.
287
288
289
290
291
292
293

294
295
296
297
298









299
300
301
302
303
304
305
**
** This is a no-op if g.userUid is 0.
*/
void login_clear_login_data(){
  if(!g.userUid){
    return;
  }else{

    /* To logout, change the cookie value to an empty string */
    cgi_set_cookie(login_cookie_name(), "",
                   login_cookie_path(), -86400);
    db_multi_exec("UPDATE user SET cookie=NULL, ipaddr=NULL, "
                  "  cexpire=0 WHERE uid=%d", g.userUid);









  }
}

/*
** WEBPAGE: login
** WEBPAGE: logout
** WEBPAGE: my







>

|



>
>
>
>
>
>
>
>
>







287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
**
** This is a no-op if g.userUid is 0.
*/
void login_clear_login_data(){
  if(!g.userUid){
    return;
  }else{
    char const * cookie = login_cookie_name(); 
    /* To logout, change the cookie value to an empty string */
    cgi_set_cookie(cookie, "",
                   login_cookie_path(), -86400);
    db_multi_exec("UPDATE user SET cookie=NULL, ipaddr=NULL, "
                  "  cexpire=0 WHERE uid=%d", g.userUid);
    cgi_replace_parameter(cookie, NULL)
      /* At the time of this writing, cgi_replace_parameter() was
      ** "NULL-value-safe", and i'm hoping the NULL doesn't cause any
      ** downstream problems here. We could alternately use "" here.
      */
      ;
    /* Potential improvement: do we want/need to skip this step for
    ** the guest user?
    */
  }
}

/*
** WEBPAGE: login
** WEBPAGE: logout
** WEBPAGE: my