Fossil SCM
json: when logging in locally to a server started with the --localauth flag, the authToken is now ignored entirely.
Commit
6dfc395a4869945a4fd85e2f3913ddb939add1f5dc3995f916d6e162f922b499
Parent
f3d3c589855b693…
4 files changed
+19
-10
+7
-8
+13
-7
+5
-4
+19
-10
| --- src/json.c | ||
| +++ src/json.c | ||
| @@ -282,12 +282,12 @@ | ||
| 282 | 282 | ** ENV means the system environment (getenv()). |
| 283 | 283 | ** |
| 284 | 284 | ** Precedence: POST.payload, GET/COOKIE/non-JSON POST, JSON POST, ENV. |
| 285 | 285 | ** |
| 286 | 286 | ** FIXME: the precedence SHOULD be: GET, POST.payload, POST, COOKIE, |
| 287 | -** ENV, but the amalgamation of the GET/POST vars makes it difficult | |
| 288 | -** for me to do that. Since fossil only uses one cookie, cookie | |
| 287 | +** ENV, but the amalgamation of the GET/POST vars makes it effectively | |
| 288 | +** impossible to do that. Since fossil only uses one cookie, cookie | |
| 289 | 289 | ** precedence isn't a real/high-priority problem. |
| 290 | 290 | */ |
| 291 | 291 | cson_value * json_getenv( char const * zKey ){ |
| 292 | 292 | cson_value * rc; |
| 293 | 293 | rc = g.json.reqPayload.o |
| @@ -630,29 +630,38 @@ | ||
| 630 | 630 | ** we will not be able to replace fossil's internal idea of the auth |
| 631 | 631 | ** info in time (and future changes to that state may cause unexpected |
| 632 | 632 | ** results). |
| 633 | 633 | ** |
| 634 | 634 | ** The result of this call are cached for future calls. |
| 635 | +** | |
| 636 | +** Special case: if g.useLocalauth is true (i.e. the --localauth flag | |
| 637 | +** was used to start the fossil server instance) and the current | |
| 638 | +** connection is "local", any authToken provided by the user is | |
| 639 | +** ignored and no new token is created: localauth mode trumps the | |
| 640 | +** authToken. | |
| 635 | 641 | */ |
| 636 | 642 | cson_value * json_auth_token(){ |
| 637 | - assert(g.json.gc.a && "json_main_bootstrap() was not called!"); | |
| 638 | - if( !g.json.authToken ){ | |
| 643 | + assert(g.json.gc.a && "json_main_bootstrap() was not called!"); | |
| 644 | + if( g.json.authToken==0 && g.noPswd==0 | |
| 645 | + /* g.noPswd==0 means the user was logged in via a local | |
| 646 | + connection using --localauth. */ | |
| 647 | + ){ | |
| 639 | 648 | /* Try to get an authorization token from GET parameter, POSTed |
| 640 | 649 | JSON, or fossil cookie (in that order). */ |
| 641 | 650 | g.json.authToken = json_getenv(FossilJsonKeys.authToken); |
| 642 | 651 | if(g.json.authToken |
| 643 | 652 | && cson_value_is_string(g.json.authToken) |
| 644 | 653 | && !PD(login_cookie_name(),NULL)){ |
| 645 | 654 | /* tell fossil to use this login info. |
| 646 | 655 | |
| 647 | - FIXME?: because the JSON bits don't carry around | |
| 648 | - login_cookie_name(), there is(?) a potential(?) login hijacking | |
| 649 | - window here. We may need to change the JSON auth token to be in | |
| 650 | - the form: login_cookie_name()=... | |
| 656 | + FIXME?: because the JSON bits don't carry around | |
| 657 | + login_cookie_name(), there is(?) a potential(?) login hijacking | |
| 658 | + window here. We may need to change the JSON auth token to be in | |
| 659 | + the form: login_cookie_name()=... | |
| 651 | 660 | |
| 652 | - Then again, the hardened cookie value helps ensure that | |
| 653 | - only a proper key/value match is valid. | |
| 661 | + Then again, the hardened cookie value helps ensure that | |
| 662 | + only a proper key/value match is valid. | |
| 654 | 663 | */ |
| 655 | 664 | cgi_replace_parameter( login_cookie_name(), cson_value_get_cstr(g.json.authToken) ); |
| 656 | 665 | }else if( g.isHTTP ){ |
| 657 | 666 | /* try fossil's conventional cookie. */ |
| 658 | 667 | /* Reminder: chicken/egg scenario regarding db access in CLI |
| 659 | 668 |
| --- src/json.c | |
| +++ src/json.c | |
| @@ -282,12 +282,12 @@ | |
| 282 | ** ENV means the system environment (getenv()). |
| 283 | ** |
| 284 | ** Precedence: POST.payload, GET/COOKIE/non-JSON POST, JSON POST, ENV. |
| 285 | ** |
| 286 | ** FIXME: the precedence SHOULD be: GET, POST.payload, POST, COOKIE, |
| 287 | ** ENV, but the amalgamation of the GET/POST vars makes it difficult |
| 288 | ** for me to do that. Since fossil only uses one cookie, cookie |
| 289 | ** precedence isn't a real/high-priority problem. |
| 290 | */ |
| 291 | cson_value * json_getenv( char const * zKey ){ |
| 292 | cson_value * rc; |
| 293 | rc = g.json.reqPayload.o |
| @@ -630,29 +630,38 @@ | |
| 630 | ** we will not be able to replace fossil's internal idea of the auth |
| 631 | ** info in time (and future changes to that state may cause unexpected |
| 632 | ** results). |
| 633 | ** |
| 634 | ** The result of this call are cached for future calls. |
| 635 | */ |
| 636 | cson_value * json_auth_token(){ |
| 637 | assert(g.json.gc.a && "json_main_bootstrap() was not called!"); |
| 638 | if( !g.json.authToken ){ |
| 639 | /* Try to get an authorization token from GET parameter, POSTed |
| 640 | JSON, or fossil cookie (in that order). */ |
| 641 | g.json.authToken = json_getenv(FossilJsonKeys.authToken); |
| 642 | if(g.json.authToken |
| 643 | && cson_value_is_string(g.json.authToken) |
| 644 | && !PD(login_cookie_name(),NULL)){ |
| 645 | /* tell fossil to use this login info. |
| 646 | |
| 647 | FIXME?: because the JSON bits don't carry around |
| 648 | login_cookie_name(), there is(?) a potential(?) login hijacking |
| 649 | window here. We may need to change the JSON auth token to be in |
| 650 | the form: login_cookie_name()=... |
| 651 | |
| 652 | Then again, the hardened cookie value helps ensure that |
| 653 | only a proper key/value match is valid. |
| 654 | */ |
| 655 | cgi_replace_parameter( login_cookie_name(), cson_value_get_cstr(g.json.authToken) ); |
| 656 | }else if( g.isHTTP ){ |
| 657 | /* try fossil's conventional cookie. */ |
| 658 | /* Reminder: chicken/egg scenario regarding db access in CLI |
| 659 |
| --- src/json.c | |
| +++ src/json.c | |
| @@ -282,12 +282,12 @@ | |
| 282 | ** ENV means the system environment (getenv()). |
| 283 | ** |
| 284 | ** Precedence: POST.payload, GET/COOKIE/non-JSON POST, JSON POST, ENV. |
| 285 | ** |
| 286 | ** FIXME: the precedence SHOULD be: GET, POST.payload, POST, COOKIE, |
| 287 | ** ENV, but the amalgamation of the GET/POST vars makes it effectively |
| 288 | ** impossible to do that. Since fossil only uses one cookie, cookie |
| 289 | ** precedence isn't a real/high-priority problem. |
| 290 | */ |
| 291 | cson_value * json_getenv( char const * zKey ){ |
| 292 | cson_value * rc; |
| 293 | rc = g.json.reqPayload.o |
| @@ -630,29 +630,38 @@ | |
| 630 | ** we will not be able to replace fossil's internal idea of the auth |
| 631 | ** info in time (and future changes to that state may cause unexpected |
| 632 | ** results). |
| 633 | ** |
| 634 | ** The result of this call are cached for future calls. |
| 635 | ** |
| 636 | ** Special case: if g.useLocalauth is true (i.e. the --localauth flag |
| 637 | ** was used to start the fossil server instance) and the current |
| 638 | ** connection is "local", any authToken provided by the user is |
| 639 | ** ignored and no new token is created: localauth mode trumps the |
| 640 | ** authToken. |
| 641 | */ |
| 642 | cson_value * json_auth_token(){ |
| 643 | assert(g.json.gc.a && "json_main_bootstrap() was not called!"); |
| 644 | if( g.json.authToken==0 && g.noPswd==0 |
| 645 | /* g.noPswd==0 means the user was logged in via a local |
| 646 | connection using --localauth. */ |
| 647 | ){ |
| 648 | /* Try to get an authorization token from GET parameter, POSTed |
| 649 | JSON, or fossil cookie (in that order). */ |
| 650 | g.json.authToken = json_getenv(FossilJsonKeys.authToken); |
| 651 | if(g.json.authToken |
| 652 | && cson_value_is_string(g.json.authToken) |
| 653 | && !PD(login_cookie_name(),NULL)){ |
| 654 | /* tell fossil to use this login info. |
| 655 | |
| 656 | FIXME?: because the JSON bits don't carry around |
| 657 | login_cookie_name(), there is(?) a potential(?) login hijacking |
| 658 | window here. We may need to change the JSON auth token to be in |
| 659 | the form: login_cookie_name()=... |
| 660 | |
| 661 | Then again, the hardened cookie value helps ensure that |
| 662 | only a proper key/value match is valid. |
| 663 | */ |
| 664 | cgi_replace_parameter( login_cookie_name(), cson_value_get_cstr(g.json.authToken) ); |
| 665 | }else if( g.isHTTP ){ |
| 666 | /* try fossil's conventional cookie. */ |
| 667 | /* Reminder: chicken/egg scenario regarding db access in CLI |
| 668 |
+7
-8
| --- src/json_login.c | ||
| +++ src/json_login.c | ||
| @@ -43,19 +43,18 @@ | ||
| 43 | 43 | FIXME: we want to check the GET/POST args in this order: |
| 44 | 44 | |
| 45 | 45 | - GET: name, n, password, p |
| 46 | 46 | - POST: name, password |
| 47 | 47 | |
| 48 | - but a bug in cgi_parameter() is breaking that, causing PD() to | |
| 49 | - return the last element of the PATH_INFO instead. | |
| 48 | + but fossil's age-old behaviour of treating the last element of | |
| 49 | + PATH_INFO as the value for the name parameter breaks that. | |
| 50 | 50 | |
| 51 | - Summary: If we check for P("name") first, then P("n"), | |
| 52 | - then ONLY a GET param of "name" will match ("n" | |
| 53 | - is not recognized). If we reverse the order of the | |
| 54 | - checks then both forms work. Strangely enough, the | |
| 51 | + Summary: If we check for P("name") first, then P("n"), then ONLY a | |
| 52 | + GET param of "name" will match ("n" is not recognized). If we | |
| 53 | + reverse the order of the checks then both forms work. The | |
| 55 | 54 | "p"/"password" check is not affected by this. |
| 56 | - */ | |
| 55 | + */ | |
| 57 | 56 | char const * name = cson_value_get_cstr(json_req_payload_get("name")); |
| 58 | 57 | char const * pw = NULL; |
| 59 | 58 | char const * anonSeed = NULL; |
| 60 | 59 | cson_value * payload = NULL; |
| 61 | 60 | int uid = 0; |
| @@ -231,11 +230,11 @@ | ||
| 231 | 230 | */ |
| 232 | 231 | cson_value * json_page_whoami(){ |
| 233 | 232 | cson_value * payload = NULL; |
| 234 | 233 | cson_object * obj = NULL; |
| 235 | 234 | Stmt q; |
| 236 | - if(!g.json.authToken){ | |
| 235 | + if(!g.json.authToken && g.userUid==0){ | |
| 237 | 236 | /* assume we just logged out. */ |
| 238 | 237 | db_prepare(&q, "SELECT login, cap FROM user WHERE login='nobody'"); |
| 239 | 238 | } |
| 240 | 239 | else{ |
| 241 | 240 | db_prepare(&q, "SELECT login, cap FROM user WHERE uid=%d", |
| 242 | 241 |
| --- src/json_login.c | |
| +++ src/json_login.c | |
| @@ -43,19 +43,18 @@ | |
| 43 | FIXME: we want to check the GET/POST args in this order: |
| 44 | |
| 45 | - GET: name, n, password, p |
| 46 | - POST: name, password |
| 47 | |
| 48 | but a bug in cgi_parameter() is breaking that, causing PD() to |
| 49 | return the last element of the PATH_INFO instead. |
| 50 | |
| 51 | Summary: If we check for P("name") first, then P("n"), |
| 52 | then ONLY a GET param of "name" will match ("n" |
| 53 | is not recognized). If we reverse the order of the |
| 54 | checks then both forms work. Strangely enough, the |
| 55 | "p"/"password" check is not affected by this. |
| 56 | */ |
| 57 | char const * name = cson_value_get_cstr(json_req_payload_get("name")); |
| 58 | char const * pw = NULL; |
| 59 | char const * anonSeed = NULL; |
| 60 | cson_value * payload = NULL; |
| 61 | int uid = 0; |
| @@ -231,11 +230,11 @@ | |
| 231 | */ |
| 232 | cson_value * json_page_whoami(){ |
| 233 | cson_value * payload = NULL; |
| 234 | cson_object * obj = NULL; |
| 235 | Stmt q; |
| 236 | if(!g.json.authToken){ |
| 237 | /* assume we just logged out. */ |
| 238 | db_prepare(&q, "SELECT login, cap FROM user WHERE login='nobody'"); |
| 239 | } |
| 240 | else{ |
| 241 | db_prepare(&q, "SELECT login, cap FROM user WHERE uid=%d", |
| 242 |
| --- src/json_login.c | |
| +++ src/json_login.c | |
| @@ -43,19 +43,18 @@ | |
| 43 | FIXME: we want to check the GET/POST args in this order: |
| 44 | |
| 45 | - GET: name, n, password, p |
| 46 | - POST: name, password |
| 47 | |
| 48 | but fossil's age-old behaviour of treating the last element of |
| 49 | PATH_INFO as the value for the name parameter breaks that. |
| 50 | |
| 51 | Summary: If we check for P("name") first, then P("n"), then ONLY a |
| 52 | GET param of "name" will match ("n" is not recognized). If we |
| 53 | reverse the order of the checks then both forms work. The |
| 54 | "p"/"password" check is not affected by this. |
| 55 | */ |
| 56 | char const * name = cson_value_get_cstr(json_req_payload_get("name")); |
| 57 | char const * pw = NULL; |
| 58 | char const * anonSeed = NULL; |
| 59 | cson_value * payload = NULL; |
| 60 | int uid = 0; |
| @@ -231,11 +230,11 @@ | |
| 230 | */ |
| 231 | cson_value * json_page_whoami(){ |
| 232 | cson_value * payload = NULL; |
| 233 | cson_object * obj = NULL; |
| 234 | Stmt q; |
| 235 | if(!g.json.authToken && g.userUid==0){ |
| 236 | /* assume we just logged out. */ |
| 237 | db_prepare(&q, "SELECT login, cap FROM user WHERE login='nobody'"); |
| 238 | } |
| 239 | else{ |
| 240 | db_prepare(&q, "SELECT login, cap FROM user WHERE uid=%d", |
| 241 |
+13
-7
| --- www/json-api/api-auth.md | ||
| +++ www/json-api/api-auth.md | ||
| @@ -148,25 +148,31 @@ | ||
| 148 | 148 | The response *also* sets the conventional fossil login cookie (for |
| 149 | 149 | clients which can make use of cookies), using fossil's existing |
| 150 | 150 | mechanism for this. |
| 151 | 151 | |
| 152 | 152 | Further requests which require authentication must include the |
| 153 | -"authToken" (from the returned payload value) in the request (or it must | |
| 153 | +`authToken` (from the returned payload value) in the request (or it must | |
| 154 | 154 | be available via fossil's standard cookie) or access may (depending on |
| 155 | -the request) be denied. The authToken may optionally be set in the | |
| 155 | +the request) be denied. The `authToken` may optionally be set in the | |
| 156 | 156 | request envelope or as a GET parameter, and it *must* be given if the |
| 157 | 157 | request requires restricted access to a resource. e.g. if reading |
| 158 | 158 | tickets is disabled for the guest user then all non-guest users must |
| 159 | 159 | send authentication info in their requests in order to be able to fetch |
| 160 | 160 | ticket info. |
| 161 | 161 | |
| 162 | 162 | Cookie-aware clients should send the login-generated cookie with each |
| 163 | -request, in which case they do not need explicitly include the auth | |
| 164 | -token in the JSON envelope/GET arguments. Note that fossil uses a | |
| 165 | -project-dependent cookie name in order to help thwart attacks, so there | |
| 166 | -is no simple mapping of cookie *name* to auth token. That said, the | |
| 167 | -cookie's *value* is also the auth token's value. | |
| 163 | +request, in which case they do not need explicitly include the | |
| 164 | +`authToken` in the JSON envelope/GET arguments. If submitted, the | |
| 165 | +`authToken` is used, otherwise the cookie, if set, is used. Note that | |
| 166 | +fossil uses a project-dependent cookie name in order to help thwart | |
| 167 | +attacks, so there is no simple mapping of cookie *name* to auth | |
| 168 | +token. That said, the cookie's *value* is also the auth token's value. | |
| 169 | + | |
| 170 | +> Special case: when accessing fossil over a local server instance | |
| 171 | +which was started with the `--localauth` flag, the `authToken` is ignored | |
| 172 | +(neither validated nor used for any form of authentication). | |
| 173 | + | |
| 168 | 174 | |
| 169 | 175 | <a id="login-anonymous"></a> |
| 170 | 176 | ## Anonymous User Logins |
| 171 | 177 | |
| 172 | 178 | The Anonymous user requires special handling because he has a random |
| 173 | 179 |
| --- www/json-api/api-auth.md | |
| +++ www/json-api/api-auth.md | |
| @@ -148,25 +148,31 @@ | |
| 148 | The response *also* sets the conventional fossil login cookie (for |
| 149 | clients which can make use of cookies), using fossil's existing |
| 150 | mechanism for this. |
| 151 | |
| 152 | Further requests which require authentication must include the |
| 153 | "authToken" (from the returned payload value) in the request (or it must |
| 154 | be available via fossil's standard cookie) or access may (depending on |
| 155 | the request) be denied. The authToken may optionally be set in the |
| 156 | request envelope or as a GET parameter, and it *must* be given if the |
| 157 | request requires restricted access to a resource. e.g. if reading |
| 158 | tickets is disabled for the guest user then all non-guest users must |
| 159 | send authentication info in their requests in order to be able to fetch |
| 160 | ticket info. |
| 161 | |
| 162 | Cookie-aware clients should send the login-generated cookie with each |
| 163 | request, in which case they do not need explicitly include the auth |
| 164 | token in the JSON envelope/GET arguments. Note that fossil uses a |
| 165 | project-dependent cookie name in order to help thwart attacks, so there |
| 166 | is no simple mapping of cookie *name* to auth token. That said, the |
| 167 | cookie's *value* is also the auth token's value. |
| 168 | |
| 169 | <a id="login-anonymous"></a> |
| 170 | ## Anonymous User Logins |
| 171 | |
| 172 | The Anonymous user requires special handling because he has a random |
| 173 |
| --- www/json-api/api-auth.md | |
| +++ www/json-api/api-auth.md | |
| @@ -148,25 +148,31 @@ | |
| 148 | The response *also* sets the conventional fossil login cookie (for |
| 149 | clients which can make use of cookies), using fossil's existing |
| 150 | mechanism for this. |
| 151 | |
| 152 | Further requests which require authentication must include the |
| 153 | `authToken` (from the returned payload value) in the request (or it must |
| 154 | be available via fossil's standard cookie) or access may (depending on |
| 155 | the request) be denied. The `authToken` may optionally be set in the |
| 156 | request envelope or as a GET parameter, and it *must* be given if the |
| 157 | request requires restricted access to a resource. e.g. if reading |
| 158 | tickets is disabled for the guest user then all non-guest users must |
| 159 | send authentication info in their requests in order to be able to fetch |
| 160 | ticket info. |
| 161 | |
| 162 | Cookie-aware clients should send the login-generated cookie with each |
| 163 | request, in which case they do not need explicitly include the |
| 164 | `authToken` in the JSON envelope/GET arguments. If submitted, the |
| 165 | `authToken` is used, otherwise the cookie, if set, is used. Note that |
| 166 | fossil uses a project-dependent cookie name in order to help thwart |
| 167 | attacks, so there is no simple mapping of cookie *name* to auth |
| 168 | token. That said, the cookie's *value* is also the auth token's value. |
| 169 | |
| 170 | > Special case: when accessing fossil over a local server instance |
| 171 | which was started with the `--localauth` flag, the `authToken` is ignored |
| 172 | (neither validated nor used for any form of authentication). |
| 173 | |
| 174 | |
| 175 | <a id="login-anonymous"></a> |
| 176 | ## Anonymous User Logins |
| 177 | |
| 178 | The Anonymous user requires special handling because he has a random |
| 179 |
+5
-4
| --- www/json-api/conventions.md | ||
| +++ www/json-api/conventions.md | ||
| @@ -73,14 +73,15 @@ | ||
| 73 | 73 | request. Determines what access rights the user has, and any given |
| 74 | 74 | request may require specific rights. In principle this is required |
| 75 | 75 | by any request which needs non-guest privileges, but cookie-aware |
| 76 | 76 | clients do not manually need to track this (it is managed as a |
| 77 | 77 | cookie by the agent/browser). |
| 78 | - - Note that when using a fossil server with the `--localauth` option, | |
| 79 | - the `authToken` should not be used. FIXME: have the JSON API simply ignore | |
| 80 | - the `authToken` for this case, rather than failing if the `authToken` | |
| 81 | - is missing or invalid. | |
| 78 | + - Note that when accessing fossil over a local server instance | |
| 79 | + which was started with the `--localauth` flag, the `authToken` | |
| 80 | + will be ignored and need not be sent with any requests. The user | |
| 81 | + will automatically be given full privileges, as if they were | |
| 82 | + using CLI mode. | |
| 82 | 83 | - `payload`: Command-specific parameters. Most can optionally come in |
| 83 | 84 | via GET parameters, but those taking complex structures expect them |
| 84 | 85 | to be placed here. |
| 85 | 86 | - `indent`: Optionally specifies indentation for the output. 0=no |
| 86 | 87 | indention. 1=a single TAB character for each level of |
| 87 | 88 |
| --- www/json-api/conventions.md | |
| +++ www/json-api/conventions.md | |
| @@ -73,14 +73,15 @@ | |
| 73 | request. Determines what access rights the user has, and any given |
| 74 | request may require specific rights. In principle this is required |
| 75 | by any request which needs non-guest privileges, but cookie-aware |
| 76 | clients do not manually need to track this (it is managed as a |
| 77 | cookie by the agent/browser). |
| 78 | - Note that when using a fossil server with the `--localauth` option, |
| 79 | the `authToken` should not be used. FIXME: have the JSON API simply ignore |
| 80 | the `authToken` for this case, rather than failing if the `authToken` |
| 81 | is missing or invalid. |
| 82 | - `payload`: Command-specific parameters. Most can optionally come in |
| 83 | via GET parameters, but those taking complex structures expect them |
| 84 | to be placed here. |
| 85 | - `indent`: Optionally specifies indentation for the output. 0=no |
| 86 | indention. 1=a single TAB character for each level of |
| 87 |
| --- www/json-api/conventions.md | |
| +++ www/json-api/conventions.md | |
| @@ -73,14 +73,15 @@ | |
| 73 | request. Determines what access rights the user has, and any given |
| 74 | request may require specific rights. In principle this is required |
| 75 | by any request which needs non-guest privileges, but cookie-aware |
| 76 | clients do not manually need to track this (it is managed as a |
| 77 | cookie by the agent/browser). |
| 78 | - Note that when accessing fossil over a local server instance |
| 79 | which was started with the `--localauth` flag, the `authToken` |
| 80 | will be ignored and need not be sent with any requests. The user |
| 81 | will automatically be given full privileges, as if they were |
| 82 | using CLI mode. |
| 83 | - `payload`: Command-specific parameters. Most can optionally come in |
| 84 | via GET parameters, but those taking complex structures expect them |
| 85 | to be placed here. |
| 86 | - `indent`: Optionally specifies indentation for the output. 0=no |
| 87 | indention. 1=a single TAB character for each level of |
| 88 |