Hypertopic / AAAforREST

An HTTP reverse proxy to bring authentication, authorization and accounting to RESTful applications
GNU Affero General Public License v3.0
6 stars 5 forks source link

Interaction with Hypertopic servers #40

Closed christophe-lejeune closed 6 years ago

christophe-lejeune commented 8 years ago

Hereunder are a few questions concerning interactions between AAAforRest and Cassandre.

benel commented 8 years ago

AAAforREST includes mentions of Single sign-on (SSO). Does it mean that AAAforRest is compliant with academic repositories managed through SSO ?

Nope.

If not, is it intended to become ?

Only if we understand how they work, if their design is "clean enough", and if we have time to do that (with a lot of interactions with system administrators).

Am I right to assume that access to resources is granted on the basis of their URI ?

Access is granted on the basis on who (authentication) doing what (method) on what (URI).

If so, this would answer one of Cassandre's issue related to URI's.

Oh? Was your problem with corpora related to access management?

How is the server supposed to interact with AAAforRest ? For instance, when a diary is created under Cassandre, the user may invite registered users. Is the server (Cassandre) supposed to add one rule in AAAforREST configuration file ? Or is it supposed to work differently ?

For now AAAforREST is isofunctional with Apache. If access to the new resource is different from the default, a rule must be added to its settings. But in the future, the rule would be defined in Cassandre, and then AAAforREST would ask Cassandre the related rules through a REST API.

benel commented 8 years ago

Note that we could also adopt a less "aesthetic" but simpler architecture (that we already tested in L4L) to handle dynamic authentication in our applications.

christophe-lejeune commented 8 years ago

Thank you very much for the answers, Aurélien.

a lot of interactions with system administrators

I am still unsure whether I will investigate SSO further...

Access is granted on the basis on who (authentication) doing what (method) on what (URI).

This indeed suggests that Cassandre's URIs should mention the corpus, in order for rules to manage who (username) can access / modify / delete resource. URI's not including corpus (as proposed here) would make the design far more complicated. This advocates to keep corpus names in URIs.

If access to the new resource is different from the default, a rule must be added to its settings.

This confirms that, in their current state, AAAforREST and Cassandre won't help to meet basic requirements for Cassandre’s collaborative features. Be sure to understand : I am not complaining. I just want to be sure I understand correctly where we are going and where my next contribution will be useful.

we could also adopt a less "aesthetic" but simpler architecture

Given our respective availability, I think such a strategy would be relevant. I guess we'd better exchange about this simpler option through personal messages... or would you like to expose it here ?

benel commented 8 years ago

Given our respective availability, I think such a strategy would be relevant. I guess we'd better exchange about this simpler option through personal messages... or would you like to expose it here ?

The simple option is to use CouchDB's "proxy authentication":

  1. The proxy handles authentication (on LDAP or other),
  2. The proxy forwards to CouchDB both the user name (and optionally roles) and a secret shared by itself and CouchDB,
  3. CouchDB which is set up to accept proxy authentication, let show and list functions access the req.userCtx object.

Note: While it can be done by Apache (or by any other reverse proxy), I recommend using AAAforREST: it is much simpler (just a single directive!), and safer (it prevents forged headers to be forwarded).

christophe-lejeune commented 8 years ago

I am currently trying to apply this option.

I see different possible reasons for this :

How do you think I may diagnose where the user name is lost in the process ?

benel commented 8 years ago

Have you set up the same "secret" in both AAAforREST and CouchDB?

christophe-lejeune commented 8 years ago

Yes. The same string value is indicated in AAAforREST config.json under "forwardedLoginSecret" and in CouchDB under couch_httpd_auth / secret.

christophe-lejeune commented 8 years ago

Are there security requirements (such as number of digits, mix of capital letters and numbers...) for this shared secret ?

benel commented 8 years ago

Once forwarded to Cassandre node/app.js, the user name may be not transmitted to CouchDB. In that case, Cassandre node/app.js would be involved.

You could shunt the node part of Cassandre (just for a test).

EDIT: Maybe not. See other suggestions first.

benel commented 8 years ago

Have you enabled proxy_use_secret (as I did for the tests: https://github.com/Hypertopic/AAAforREST/blob/master/.travis.yml#L53)?

benel commented 8 years ago

Is proxy_authentication_handler enabled (as done here: https://github.com/Hypertopic/AAAforREST/blob/master/.travis.yml#L52)?

christophe-lejeune commented 8 years ago

Here are some other settings that could be involved in CouchDB :

Section Option Value
couch_httpd_auth proxy_use_secret true
require_valid_user false
http authentication_handlers {couch_httpd_auth, cookie_authentication_handler}, {couch_httpd_auth, proxy_authentication_handler}, {couch_httpd_auth, default_authentication_handler}

This is a copy of my current configuration.

christophe-lejeune commented 8 years ago

You could shunt the node part of Cassandre (just for a test).

Here is what I have tested :

function(o, req){
  var data = {
    logged: req.userCtx.name,
  }
  return Mustache.to_html(templates.x, data);
}

The related template include console.log({{logged}}); According to Firebug, this string is undefined.

However, according to AAAforREST, this test is irrelevant, given I am not browsing the server though port 80. As a consequence, it is normal that no user is forwarded. Have you any suggestion in order for me to shunt the node part of Cassandre and however browse through port 80 ?

christophe-lejeune commented 8 years ago

The latter test was not far to be relevant. It was conducted through the port 80, as confirmed by AAAforREST logs. While logs mention a user name, the show described in my previous post desperately reports a undefined user name.

christophe-lejeune commented 8 years ago

I think I got it. This problem is related to another issue. I conduct some tests and give you more information soon.

christophe-lejeune commented 8 years ago

Here we are.

Everything thus works as expected... for some proxy rules / config. Everything is not yet clear for me at this stage. It is likely that the issues I faced are due to my lack of experience with AAAforREST.

What I can say is :

I'll post complimentary findings once I'll have tested these features further.

Again many thanks to Aurélien for his precious and patient help.

benel commented 8 years ago
  • Under selected circumstances, AAAforREST accurately forward the user name to the backend.
  • The node part of Cassandre also transmits the username to list and show.

Good. Please note that the settings I gave you was using authenticateIfPresent (rather than authenticate): it doesn't force you to authenticate. So it's possible that you won't get a user context on a resource if your app or the proxy doesn't send any 401.

If you need to display the username on the screen (and therefore get the user context on GET), you may have to use cookie authentication.

@franck-eyraud Can you confirm?

franck-eyraud commented 8 years ago

If you need to display the username on the screen (and therefore get the user context on GET), you may have to use cookie authentication.

@franck-eyraud Can you confirm?

Not quite. Cookie authentication just allows to use a login form once and not send the credentials with each request (in the http headers). But username forwarding (which allows to display it on the screen) should work the same in both cases.

benel commented 8 years ago

Not quite. Cookie authentication just allows to use a login form once and not send the credentials with each request (in the http headers). But username forwarding should work the same in both cases.

Sure, AAAforREST handles it the same way. But I suspect that the browser might handle it differently. I must test it but the problems encountered by Christophe could be caused by a lazy behavior of the the browser with basic authentication:

  1. GET /public -> 200
  2. GET /private1 -> 401
  3. Ask for user & password
  4. GET /private1 as user:password -> 200
  5. GET /private2 -> 401
  6. GET /private2 as user:password -> 200
  7. GET /public -> 200

=> On this page, the app doesn't know who I am.

Whereas:

  1. GET /public
  2. POST /session with user & password
  3. GET /private with session
  4. GET /public with session

=> On this page, the page knows who I am.

Am I assuming incorrectly the behavior of browsers?

franck-eyraud commented 8 years ago

OK, I see now (I didn't get exactly the whole picture, I started to get notifications on this issue only when you poked me)

Yes, you might be right, I have never met this case, but for sure, basic auth has a lot of limitations, and this could be yet another one... The server cannot force the browser to send authentication if it doesn't really need it... http://stackoverflow.com/questions/14418597/optional-http-basic-auth

The behavior could be browser-dependent. They usually have an optimization mechanism to not always try without auth, wait for 401, then send auth for each url, but they might record on each url if authentication was requested, or not, and not send it when not required. It is also a security matter : it might lead to send the credentials to other parts (applications) of the same domain which shouldn't see this application credentials..

benel commented 8 years ago

Well, personally, i would not blame too badly a session-less architecture for being session-less. But for sure, this means that @christophe-lejeune will have to enable cookie-authentication in order to display the current user in the menu bar.

franck-eyraud commented 8 years ago

Well, personally i would not blame too badly a session-less architecture for being session-less.

:+1: You said it a better way :)

christophe-lejeune commented 8 years ago

At this stage, my tests with Firefox suggest that, once the user:password was asked, the browser still transmits it to any page of the same domain, even when not asked for. This means that, in the example of basic authentication drawn by Aurélien, the app still knows who I am at step 7. I'll document further these behaviors in tests to come.

benel commented 8 years ago

the app still knows who I am at step 7

You are right. I was wrong.

Here is a small couchapp to test this:

rewrites.json

[{
  "from": "public",
  "to": "_show/whoami"
},{
  "from": "private1",
  "to": "_show/whoami",
  "query":{"restricted": "true"}
},{
  "from": "private2",
  "to": "_show/whoami",
  "query":{"restricted": "true"}
}]

shows/whoami.js

function(doc, req) {  
  if (req.query.restricted && !req.userCtx.name) 
    return {
      code: 401,
      headers: {
        'WWW-Authenticate': 'Basic realm="Wonderland"'
      }
    };
  send('<a href="public">Public</a> ');
  send('<a href="private1">Private1</a> ');
  send('<a href="private2">Private2</a>');
  send('<p>I am ' + req.userCtx.name + '</p>');
}

To be opened with http://127.0.0.1:5984/test/_design/whoami/_rewrite/public

Tested on Safari, Firefox and Chrome.

Note: This basic test doesn't use AAAforREST. Authentication is done by CouchDB and authorization by the couchapp.

franck-eyraud commented 8 years ago

Warning, this might be true now and here, but it could change in the future, or in different browsers, I wouldn't rely too much on it in the long term.

in particular, if you change the show with these three lines :

  send('<a href="../public/">Public</a> ');
  send('<a href="../private1/">Private1</a> ');
  send('<a href="../private2/">Private2</a>');

and browse instead to http://127.0.0.1:5984/test/_design/whoami/_rewrite/public/ (trailing slash), you get a different result, which is very obvious at first sight.

benel commented 8 years ago

Warning, this might be true now and here, but it could change in the future

True, but don't forget my original aim was not to develop a new app but just to reproduce the problem found by Christophe ;) I'm trying to to add one stack at a time and determine if it still works as we think it should.

franck-eyraud commented 8 years ago

Warning, this might be true now and here, but it could change in the future, or in different browsers, I wouldn't rely too much on it in the long term.

To be honest, I didn't check the HTTP standards. If it is well described there, then it could be relied on.

franck-eyraud commented 8 years ago

True, but don't forget my original aim was not to develop a new app but just to reproduce the problem found by Christophe ;)

Yes, I know, my warning was more directed to him.

christophe-lejeune commented 8 years ago

Thank you very much for your advices and counsels.

The tests I was conducting before I found a solution are not totally reliable, given I was using console.log({{logged}});, which yields the app to consider my user name as the name of an undefined variable.

Instead, I should have used console.log("{{logged}}");. Current tests are using the right syntax (I hope).

Here are my preliminary results.

As before, my tests are conducted with the Iceweasel browser, a debian-flavored Firefox. Note that I am using a config.json mentioning two different LDAP's (my university's one and Dolomite). Here are the rule and restrictions tested :

    "restricted": {
      "dance": ["university.username"]
    },
    "restricted": {
      "suffer": ["hypertopic.username"]
    },
    "rules": [{
      "control": "true",
      "action": "authenticate(context, function(){authorize(context, function(){proxyWork(context);});});"
    }]

For convenience, this configuration uses human-readable diary ids ("dance", "suffer"). Other diaries exist, but no rule are dedicated to them. This is intended and is part of my test. Inspired by a previous configuration, the "rule" is intended to "force" authentication (which it does).

Creating a diary while authenticated does not work properly but it is related to another issue, due to my code (I guess). I'll discuss that issue elsewhere, when I will have gathered enough elements.

I will conduct the same test with another rule later... And I won't miss to conduct the test that Aurélien writes up for me four hours ago.

Do not hesitate to ask me to test other rules and/or to share insights on why the access is not granted as intended.

benel commented 8 years ago

@franck-eyraud I set up AAAforREST so that it forwards login to CouchDB on success.

In CouchDB I got the following debug logs:

"X-Auth-Couchdb-Roles":"protect",
"X-Auth-Couchdb-Token":"7dda2e792b1ac9bde472ef648b850b49d3bee3be",
"X-Auth-Couchdb-Username":"alice"
{"db":"test","name":null,"roles":["_admin"]}

What could explain that the header don't have any effect on userCtx?

franck-eyraud commented 8 years ago

If we consider that you correctly set the secret on both sides, you might not have activated proxy auth on CouchDB side. Check what is the output of an authenticated request to /_session. In info part, you should have the value proxy in authentication_handlers list.

Like that :

{
    "info": {
        "authenticated": "proxy", 
        "authentication_db": "_users", 
        "authentication_handlers": [
            "default", 
            "proxy", 
            "cookie"
        ]
    }, 
    "ok": true, 
    "userCtx": {
        "name": "alice", 
        "roles": [
            "protect"
        ]
    }
}

If not, you need to include {couch_httpd_auth, proxy_authentication_handler} in the comma separated list of config value httpd/authentication_handlers

christophe-lejeune commented 8 years ago

Here are the results of my second test. The only change since my previous test concerns AAAforREST rule.

    "restricted": {
      "dance": ["university.username"]
    },
    "restricted": {
      "suffer": ["hypertopic.username"]
    },
    "rules": [{
      "control": "true",
      "action": "authenticateIfPresent(context,function(){proxyWork(context)})"
    }]

Browsing any diary (restricted or not) and creating memos, comments, diagrams and graphs are allowed without authentication.

Thus, as far as I understand, authenticateIfPresent is useless when control is "true". I suppose it become useful with a control such as method != 'GET'(although not tested yet). I may need a course on the syntax of the rule in AAAforREST. Do not hesitate to indicate some documentation I could read.

christophe-lejeune commented 8 years ago

Third test

    "restricted": {
      "dance": ["university.username"]
    },
    "restricted": {
      "suffer": ["hypertopic.username"]
    },
    "rules": [{
      "control": "method != 'GET'",
      "action": "authenticateIfPresent(context,function(){proxyWork(context)})"
    }]

As in second test, any action is allowed without authentication. I definitely do not understand how to use authenticateIfPresent.

benel commented 8 years ago

Thus, as far as I understand, authenticateIfPresent is useless when control is "true".

It shouldn't be useless if authorization was handled by the upstream server (such as Cassandre). That's why I wrote this configuration, since I guessed that you wanted Cassandre to handle the ACL.

christophe-lejeune commented 8 years ago

This is the first time I come to realize that Cassandre could do anything related to ACL. It would indeed be possible to save some restrictions (chosen by the user) when a diary is created. Up to now, I never envisage that Cassandre could handle ACL by itself. I mean, ACL is of course one of Cassandre's feature, but I did think it was too soon to propose it.

In fact, my principal purpose, at this stage, is to provide a usable service for the next academic year. I consider that choosing the simplest option is the best guarantee for this purpose to be achieved. And up to now, I was thinking that managing access through AAAforREST (only) was the simplest/best option.

What I had in mind, as far as I can foresee it, is a basic usable service, that would require the following.

My assumption was that such a behavior does not require full ACL. I could manually modify AAAforREST config file's in order for each team diary id (part of URL) to be "restricted" to student user name that belong to the team. Once a user is logged, his/her activity could be tracked and recorded (especially when (s)he create, modify or update something.

As I wrote earlier, I am still unsure how far Cassandre should handle ACL at this stage. What do you think of my (here above) assumptions ? They sound reasonable to you ? Or should I be more ambitious ? Do you think (as suggested by your previous comment) that integrating more ACL features into Cassandre would be easily feasible ? The more I think about it, the more I think that it should be too complicated to let the diary creator pick some team members... and/or, similarly to choose whether (s)er want to share the memo (s)he is creating.

christophe-lejeune commented 8 years ago

What precedes does not prevent to propose a button allowing to authenticate, switch user or logout.

The need for such a button seems confirmed by tests conducted with Firefox suggested, showing that the browser keep sending the user name after authentication.

Such a button should not imply to use cookie authentication, am I right ? @franck-eyraud , have you any insight on how code such a button ?

christophe-lejeune commented 8 years ago

I have tested the couchapp that @benel have written. In my test (run with Firefox), the user is not asked a password for Public. A password is asked for Private1 & Private2 but access is given even if the prompt is escaped.

franck-eyraud commented 8 years ago

What precedes does not prevent to propose a button allowing to authenticate, switch user or logout.

The need for such a button seems confirmed by tests conducted with Firefox suggested, showing that the browser keep sending the user name after authentication.

Such a button should not imply to use cookie authentication, am I right ? @franck-eyraud , have you any insight on how code such a button ?

I'm not really sure. Yes, you can have a button for changing from unauthenticated to authenticated (this is the behaviour illustrated by Aurelien's couchapp), but to logout and switch user... I don't think it is possible. The link I previously posted says that with basic HTTP Auth "there is no concept of logging out", and even changing user, I don't see it possible, because even if one url forces you to authenticate again by sending a 401 HTTP error code, without a cookie, you cannot know if it is reached with the old credentials or the new ones to discriminate from allowing/denying access (when getting a 401, the browser asks for credentials and repeat the exact same request). That wouldn't be an authentication cookie, just a status cookie. But maybe it would be worth it to go for cookie authentication (in CouchDB, with internal users, it is set up by default, because used by the admin interface. But it requires some javascript on the client side...)

A password is asked for Private1 & Private2 but access is given even if the prompt is escaped.

What do you mean "if the prompt is escaped" ? If no user is authenticated, access should be denied (in Firefox I get blank page)

benel commented 8 years ago
"restricted": {
  "dance": ["university.username"]
},
"restricted": {
  "suffer": ["hypertopic.username"]
},

While this is a syntactically correct JSON part, it is not "semantically" correct. Because you have the same key twice, the first value will be replaced by the second.

Yet again please use config.sample.js as the official sample (as said in the README) rather than config.sample.json which is just the configuration needed by the tests. The official sample is much more complete and commented.

Please replace your former extract with:

"restricted": {
  "dance": ["university.username"],
  "suffer": ["hypertopic.username"]
},
benel commented 8 years ago

As I wrote earlier, I am still unsure how far Cassandre should handle ACL at this stage. What do you think of my (here above) assumptions ?

In both cases there are some types of ACL:

I suggest that you begin with the first option (which should be easy as it is very similar to what we already do in Troyes), and, in the next weeks, I will try to bring here a proof of concept of the second option.

benel commented 8 years ago

{"db":"test","name":null,"roles":["_admin"]} What could explain that the header don't have any effect on userCtx?

Silly me. That was just because CouchDB was set up in "admin party" mode. In normal mode, userCtx is as it should be:

{"db":"test","name":"alice","roles":["protect"]}
benel commented 8 years ago

For complete reference, here is my config.json:

{
  "authentication":{"login":"alice", "password": "whiterabbit"},
  "sites":[{
    "hostProxy": "whoami.local",
    "port": 5984,
    "path": "/test/_design/whoami/_rewrite",
    "hideLocationParts": 1,
    "authentication": [
      {"login":"alice", "password": "whiterabbit"},
      {"login": "mrwhite", "password": "imlate"}
    ],
    "forwardedLoginSecret": "ssshhhhhhhDon'tTellAnyone",
    "rules":[{
      "control": "true",
      "action": "authenticateIfPresent(context,function(){proxyWork(context)})"
    }]
  }]
}
benel commented 8 years ago

And here is a (working!) proof of concept with ACL stored in documents:

_id

_design/whoami

_docs

{ 
  "_id":"rabbitHole",
  "title": "Burning with curiosity, you run across the field after the rabbit and are just in time to see it pop down a large rabbit-hole, under the hedge. In another moment, down you go after it!"
}
{ 
  "_id":"rabbitHouse",
  "title": "You come upon a neat little house, on the door of which was a bright brass plate with the name 'W. RABBIT' engraved upon it.",
  "readers":["mrwhite"]
}
{ 
  "_id":"wonderland",
  "title": "You open the door and find that it leads into a small passage, not much larger than a rat-hole; you kneel down and look along the passage into the loveliest garden you ever saw.",
  "readers": ["mrwhite","alice"]
}

rewrites.json

[{
  "from": ":doc",
  "to": "_show/whoami/:doc"
}]

shows/whoami.js

function(o, req) {  
  if (o.readers && o.readers.indexOf(req.userCtx.name)==-1) 
    return {
      code: 401,
      headers: {
        'WWW-Authenticate': 'Basic realm="Wonderland"'
      },
      body: "No, you can't!"
    };
  send('<a href="rabbitHole">Rabbit hole</a> ');
  send('<a href="wonderland">Wonderland</a> ');
  send('<a href="rabbitHouse">Rabbit house</a>');
  send('<p>You are ' + req.userCtx.name + '. ' + o.title + '</p>');
}

Then, open http://whoami.local/rabbitHole. Voilà: everyone can go into the rabbit hole; Alice and Mr White can visit Wonderland; and Mr White is the only one to be able to enter his house.

benel commented 8 years ago

in the next weeks, I will try to bring here a proof of concept of the second option.

It was easier than what I expected this morning. ^^

Well, to be fairly honest, the proof of concept, to be complete, would need a validate function which would do a similar thing on contributors to control who edit documents.

benel commented 8 years ago

Well, to be fairly honest, the proof of concept, to be complete, would need a validate function which would do a similar thing on contributors to control who edit documents.

Here is the missing code:

validate_doc_update.js

function(o2, o, userCtx) {
  if (!userCtx.name || o && o.contributors && o.contributors.indexOf(userCtx.name)==-1)
    throw({
      unauthorized: 'User ' + userCtx.name
        + ' is not authorized to edit this document!'
    });
}

rewrites.json

[{
  "method": "GET",
  "from": ":doc",
  "to": "_show/whoami/:doc"
}, {
  "from": ":doc",
  "to": "../../:doc"
}]

Since my little app doesn't have any edit user interface, we have to use RESTClient to test ACLs on POST/PUT/DELETE:

  1. As an anonymous user, try to create a new document.
  2. The system tells you cannot.
  3. As Alice, try to create a new document.
  4. Creation succeeds.
  5. As Alice, define Mr White as the only member of contributors.
  6. Update succeeds.
  7. As Alice, try to modify the document.
  8. The system tells you cannot.
  9. As Mr White, try to modify the document.
  10. Update succeeds.
benel commented 8 years ago

As a final step, here is how to replace HTTP basic authentication with a session cookie.

Add this in your AAAforREST site configuration:

"sessionHandler": {
  "path": "/_session"
},

Change shows/whoami.js into:

function(o, req) {
  var Mustache = require('lib/mustache');
  return Mustache.render(this.templates.place, {
    name: req.userCtx.name,
    authorized: !o.readers || o.readers.indexOf(req.userCtx.name)>-1,
    title: o.title
  });
}

and templates/place.html into:

<script src="https://code.jquery.com/jquery-2.2.4.min.js"
  integrity="sha256-BbhdlvQf/xTY9gja0Dq3HiwQF8LaCRTXxZKRutelT44="
  crossorigin="anonymous">
</script>

<header>
  {{^name}}
    <form id="signin">
      <input type="text" name="name" placeholder="username"/>
      <input type="password" name="password" placeholder="password"/>
      <button type="submit">Sign in</button>
    </form>
  {{/name}}
  {{#name}}
    {{name}}
    <button id="signout">Sign out</button>
  {{/name}}
</header>

<nav>
  <a href="rabbitHole">Rabbit hole</a>
  <a href="wonderland">Wonderland</a>
  <a href="rabbitHouse">Rabbit house</a>
</nav>

<article>
  {{^authorized}}
    <p>You shouldn't be there.</p>
  {{/authorized}}
  {{#authorized}}
    <p>{{title}}</p>
  {{/authorized}}
</article>

<script>

var reload = function() {
  location.reload();
};

$('#signin').on('submit', function(e) {
  e.preventDefault();
  $.post('_session', $(this).serialize(), reload);
});

$('#signout').on('click', function() {
  $.ajax({
    type: 'DELETE',
    url: '_session',
    success: reload
  });
});

</script>

@christophe-lejeune Voilà. Hope this helps.

christophe-lejeune commented 8 years ago

Thank you very much, @benel for this proof of concept. This helps a lot, of course !

I am currently testing the validate function. As @benel mentioned, the proof of concept involves the RESTClient. A Hypertopic server (such as Cassandre) provides Web forms to create, update or delete documents.

If I understand correctly, these forms should behave as the RESTClient : they should submit the user & the password to the server. Thus, while the Hypertopic server let AAAforREST interacts in case of GET method, it should catch the password for PUT, POST & DELETE methods.

Does my assumptions sound right ? Is such a strategy consistent with what we previously designed ? What do you think ?

PS: My tests have been conducted with HTTP basic authentication, not with a session cookie.

christophe-lejeune commented 8 years ago

Session cookie tested and approved. With session cookie enabled, validation works nicely inside Hypertopic server, making my last question irrelevant.

This now works like a charm, and almost "out of the box" ;-) Thank you @benel for the huge amount of work you provide to us !

If you or other people want session cookie to properly function on Hypertopic servers, do not forget to add a slash to the target '/_session' URL in the sign in/out form code. I mention this only for documentary purpose.

Some elements of my own setup still need to be fixed :

franck-eyraud commented 8 years ago

If I understand correctly, these forms should behave as the RESTClient : they should submit the user & the password to the server. Thus, while the Hypertopic server let AAAforREST interacts in case of GET method, it should catch the password for PUT, POST & DELETE methods.

Does my assumptions sound right ? Is such a strategy consistent with what we previously designed ? What do you think ?

Maybe you already answered these question in the mean time, but if not, I'm not sure if you are talking about login forms or edit forms ?

I am henceforth unable to modify a document through Futon (in Admin Party) : even outside the Hypertopic application, the validate function complains that null user is not allowed to perform such actions. The validate function should not prevent unidentified users to add/modify 'public' elements.

I suppose the validate function proposed by Aurélien leaves place for improvement for those specific cases. In particular, giving access to administrators not listed in the list of user by document can be done by testing :

var is_admin=userCtx.roles.indexOf("_admin")!=-1;
if (is_admin) return; //accept modification

You can write a similar code to allow any modification of public documents (if such information is stored).

Interesting topic, because user authorization is something that will need to be done also for TraduXio

christophe-lejeune commented 8 years ago

Thank you very much for your help @franck-eyraud : your code helped a lot to recover admin access to my test server DB ;-) I'll go further in testing let you know about my code as soon as possible !