Ticket #463 (closed Feature Request: worksforme)

Opened 7 years ago

Last modified 7 years ago

dm4-sign-on: implementing an OpenID-consuming plugin

Reported by: Malte Owned by: Malte
Priority: Major Milestone:
Component: DeepaMehta Standard Distribution Version:
Keywords: Cc: jri, dgf
Complexity: 3 Area: GUI / Usability
Module: deepamehta-accesscontrol

Description

Model an URL (OpenID Service Provider Endpoint) to a DeepaMehta "User Account".

This sign-on plugin shall be aware of any "User Account" "Blocked" semantics and, in case, deny access despite a correct authentication via Auth-Service-Provider.

Change History

comment:1 Changed 7 years ago by Malte

  • Type changed from Defect to Feature Request

comment:2 Changed 7 years ago by Malte

And a sucessfull "sign-on" should create a valid DeepaMehta "HTTP Session" for any "User Account" associated with the given OpenID.

comment:3 Changed 7 years ago by Malte

Research which brought us to this idea:

see https://code.google.com/p/openid4java/wiki/SampleConsumer

comment:4 Changed 7 years ago by Malte

While implementing a very basic first version of OpenId? Authentication for DeepaMehta, I ran into the following issues with the framework:

  • with a dm-setup (setting: write_requires_login=true) a user cannot self-register because' she's not logged in
  • the user cannot be set as creator/owner (to get "personal edit"-permissions) since during creation there is no account yet
  • i was unable to initiate a (http-) session after getting back an "Login OK" response from an OpenID Provider

The plugin would be basically functional (without editing capabilities for an account) as soon as we can find a working solution for the last mentioned issue.

comment:5 Changed 7 years ago by Malte

And one more issue comes to mind:

  • a "User Account" created through an OpenID Provider has no password (stored in dm), but a username

So we will have to provide an alternative login-dialog for OpenID Accounts and block the standard-login (with empty passwords) of OpenID based "User Accounts" automatically somehow

Last edited 7 years ago by Malte (previous) (diff)

comment:6 Changed 7 years ago by Malte

I experimented with a lightweight openId Java implementation, https://code.google.com/p/jopenid/wiki/JOpenId, since as it turned out, the before mentioned lib just ships with massive dependencies.

comment:7 Changed 7 years ago by jri

  • Cc dgf added

comment:8 Changed 7 years ago by jri

That's great, Malte, you advance this topic!

My suggestion here is to use the opportunity to do it the right way now. That is to extend the DM framework (the Access Control module in particular) so it can deal with different authentication providers. Some basic points:

  • A developer can provide a DM module that registers an authentication provider. An authentication provider is responsible for telling if certain credentials are valid.
  • While registration a DM user can choose one authentication provider. So each "user identity" is assigned to one authentication provider.
  • A user identity can be attributed with authentication provider-specific values. The authentication provider can access these values when checking credentials.
  • If no authentication provider is registered the Access Control module falls back to a default provider (part of the Access Control module). The default provider relies on the "User Account" and "Password" types as used now.

Data model + logic:

  • DM Global: a "User Identity" consist of a "Username" and a reference to a "authentication provider" (e.g. by URI). Each DM user is represented by an User Identity instance. Its Username topic is used e.g. to represent workspace memberships (like now).
  • The "User Account" and "Password" types are no longer mandatory. They have meaning only to the default authentication provider.
  • The authentication provider interface has a method checkCredentials() that is passed a User Identity and credentials.
  • The login dialog is used globally (possibly customizable by specific authentication providers). The Login button calls the checkCredentials() of the authentication provider that is assigned to the current User Identity (identified by the entered username).

That is "User Account" and "Password" have no global semantics anymore. Instead "User Identity" and "Username" have.

Lets discuss this further. Once we settled the basic points I could implement it quickly.

comment:9 Changed 7 years ago by Malte

Ok, to wrap up your points a bit: The ACL-Module shall integrate the dm4-sign-on module through providing two new main features (introducing them to AuthenticationProviders?):

  • Self-registration via OpenID-Authentication, meaning creating a new "User Identity" based on a successfull OpenID-Authentication, if username is not already present.
  • Login to DeepaMehta via OpenID-Authentication, meaning creating a valid HTTPSession for the successfully given "User Identity". If username is already present, a HTTPSession could be started for this "User Identity" (given the security concept of OpenId?). How to successfully detect and prevent request forgery is to be investigated.

Regarding this, please note that for a possible checkCredentials()-method related to OpenID-Authentication:

And sure, if we want to do it proper now, please let's not ignore #42 (which says that a "User Identity" shall have a "Display name" which is editable by the user), as well it would be a must for the next round of improvement here, that an end-user (e.g. user "admin") is able to "Block" certain "user account"/ "user identity" (see #462).

A UX issue might also be, a "User Account" related to an "OpenID Authentication Provider" will (at first) never be able to log-in via normal password-based login dialog, resp. would have to choose in advance her authentication method.

Thanks for bringing in the framework-sight into this developments and also your motivation to implement this quickly, but currently I think if we keep this topic to it's minimal, we could complement each other developments at best.

Last edited 7 years ago by Malte (previous) (diff)

comment:10 Changed 7 years ago by Malte

But to fuel the discussion a bit:

  • It's very likely for a "sign-on/login" dialog to be customized designed proprietarily (by a DeepaMehta Provider). Therefore if we can't make the self-registration/login dialog highly customizable from the beginning (which probably evaluates to RESTful), in my opinion, the more minimal approach going for an extra-plugin way may be the way to go for now when we want to finish this within the next couple of weeks.
  • This issue should also be seen in context of the use-case it derived from: It's an add-on, a side-issue of the self-registration #405. Please take a deep look at the exact requirements of this ticket because, if the planning of our next step does not solve the original issue, meaning, if we are not able to extend the ACL-Module about the self-registration process, (which is independent of an optional OpenId?-Authentication processed discussed in this ticket,) this push seems not directly useful for me.
  • If we want to do it right, we shouldn't discuss "User Identity" and "Authentication Providers" without having actually OAuth 2.0 in sight. Because there is no way around for us to support this anytime soon if DeepaMehta wants to access any WebService? out there in the name of its users. But there DeepaMehta must first be able to keep a secret (see #419).
  • Also keep in mind the pletora of usage scenarios for OpenID, e.g. a minmial "dm4-sign-on" module providing OpenID -Authentication could also be useful for DeepaMehta friends who just want to easily enable others "sign a petition" through their Open-Identity, create a "Person"-Item in DM but not a real DM "User identity".

To support our discussion I just released the implementation of one of the two plugins tackling Open-Id-Sig-on. The code might be useful for you and others wanting to have a closer look into this topic now and it highlights better the uncritical changes we would need to be implemented in the ACL-Module to get us going with a "worksforme" solution in the upcoming weeks.

See the plugins current state here https://github.com/mukil/org.deepamehta-sign-on

Thank you & nice greetings!

comment:11 Changed 7 years ago by jri

Thanks, Malte, for the phone talk!

Now I understand that you aim to handle authentication outside DM, that is via the OpenID provider's web form and then let the OpenID provider redirect to the DM webclient.

However what I don't yet understand: how can the redirect transfer the confirmed user identity to the DM server in order to let it create an user-bound HTTP session? How could this even possible if the original login request is not seen by the DM server at all?

You suggested DM could provide a public service method with the semantics of "login as user X" but without providing any secret. From my point of view this would render the whole idea of authentication pointless. Why should a user login via OpenID (involving a secret) at all when DM would provide a means to create an user-bound HTTP session without involving any secret?

From my point of view we can pursue 2 approaches now:

  1. Learn more about OpenID and its approach to transfer a confirmed user identity to the relying party (here: DM) in case the OpenID provider's web form is used for login.
  1. Do not use the OpenID provider's web form for login but a DM login dialog. The DM server then requests the OpenID provider to confirm the credentials (involving the secret), and, if successful, creates the user-bound HTTP session.

According to what I've learned so far from http://en.wikipedia.org/wiki/OpenID both approaches are explicitly supported and reflected by OpenID's checkid_setup (approach 1.) vs. checkid_immediate (approach 2.) modes.

I would encourage to aim for approach 2 as it perfectly fits semantics of DM's current login request (including session creation). Furthermore it would provide for a better user experience as no external web form would be involved for login.

comment:12 Changed 7 years ago by Malte

Excuse me for obscuring the obvious: Yes outside DM for sure, #405 was always about a seperate UI and relating to your idea of DM providing an alterantive OpenId?-Webform where we as a RP ask our end-users (in our login-dialog) for their secret for an AP sounds just wrong.

You suggested:

  1. Do not use the OpenID provider's web form for login but a DM login dialog.

Let me try to say why i think so:

  1. I am working on a use-case where there shall be no DM webform/webclient login-dialog involved (similar scope of #405).
  2. DeepaMehta must not see any secret of a user chosing OpenId?-Auth (cause _that_ would subvert the security-idea of OpenID based Authentication for poeple).


  1. Learn more about OpenID and its approach to transfer a confirmed user identity to the relying party (here: DM) in case the OpenID provider's web form is used for login.

Check the attached code and it's processAuthenticationResponse(), hint: all the infos come to DM via @QueryParams?.

.. DM would provide a means to create an user-bound HTTP session without involving any secret?

See, the Response which may create a user-bound HTTP-session involves no secret, that's correct. It get's its validity through relating to the initial AuthenticationRequest? to an AP via certain URL-Parameter (which DM get to know).

And here I was very unlucky with choosing my words,

  • If we want to do it right, we shouldn't discuss "User Identity" and "Authentication Providers" without having actually OAuth 2.0 in sight.

So just that you get me right: Surely I support switchin from a "User Account" to a "User Identity" and implement various APs in general, it sounds like a good idea, and i am happy to discuss further details in that direction but as I pointed it out, this might be tricky to implement with OpenID-baseb-Auth and the new way of implementing Authentication in DM as you described above (see more about the OpenIDs Request/Response? relation above).

Last edited 7 years ago by Malte (previous) (diff)

comment:13 Changed 7 years ago by Malte

.. Since now we all know a bit more about relying on OpenID for user/session-authentication with DM here are some news.

Progress was made since I now found out how my HttpRequest? (to the so called AP) and the Response (of that AP) can be associated within my plugin across methods. A simple HttpSession? is used to carry along a shared secret.

Additionally with using the @Context-Annotation (thanks for that hint, jri) I now have an instance variable on my plugin providing me access to the respective HttpServletRequest?-Object. Thus I am able to create a HttpSession? manually for the first time. That was the only blocker left before progressing to this state of development.

Here is what the current state of this plugin enables us:

  • visitors can create a new DeepaMehta Account through authenticating to their existing Google or Yahoo account
  • users (DM accounts created via this plugin / or acocunts having an OpenID-URI set manually) can log in and start a working DeepaMehta Session

The only todo now left here for me now is prevent a replay attack, but now that is just a bit of routine work. So now I would be very please to find help with tackling these remaining 2 issues so that this stuff gets out of my development environment and into the world.

Here are the two remaining issues I face described in more detail:
(I could solve both issues but just in my development environment..)

Issue 1: A "Session data inconsistency: \"username\" attribute is missing"-Exception blocks my plugin from processing a response from my AP

Since a "Session" is used as a mean to transport 'shared secret' to AP (and back) when a successfull authentication response (from an AP) is recevied by my plugins RP endpoint, ACL Plugins username()-method interfers (throws an Exception). I understand this since this is due to the fact that there already is a HttpSession? object available but that is not (yet) a proper "DeepaMehta Session" since "Username" is missing.

Please note that in this case, when my plugins receives a proper response from an AP, there is not yet a "Username" known, so there cannot be a "proper" session. Account creation is yet to be performed but ACLPlugin (in it's current implementation) does block the response of reaching my plugins method implementation.

Through removing the session consistency Exception from the ACLsPlugin method username() implementation, my plugin was successfully able to work around this issue, receive the response from an AP and go on from there to create a new user account.

Issue 2: Creating a new user account without having a "ClientState?".

This plugin needs to be able to create a Topic without having a clientState (and thus be able to set all ACLs on that new user-account topic manually after creation).

dms.createTopic(new TopicModel(..), null);  // clientState=null

But here is what I get when I try:

...

	at de.deepamehta.core.impl.EmbeddedService.createTopic(EmbeddedService.java:168)
	at de.deepamehta.core.impl.ValueStorage.storeCompositionOne(ValueStorage.java:292)
	at de.deepamehta.core.impl.ValueStorage.storeChildTopics(ValueStorage.java:271)
	at de.deepamehta.core.impl.ValueStorage.storeCompositeValue(ValueStorage.java:255)
	... 47 more
Caused by: java.lang.RuntimeException: Processing event POST_CREATE_TOPIC by plugin "DeepaMehta 4 Access Control" failed
	at de.deepamehta.core.impl.EventManager.deliverEvent(EventManager.java:63)
	at de.deepamehta.core.impl.EventManager.fireEvent(EventManager.java:49)
	at de.deepamehta.core.impl.EmbeddedService.fireEvent(EmbeddedService.java:601)
	at de.deepamehta.core.impl.EmbeddedService.createTopic(EmbeddedService.java:162)
	... 50 more
Caused by: java.lang.RuntimeException: Setting the creator of object 3063 failed
	at de.deepamehta.plugins.accesscontrol.AccessControlPlugin.setCreator(AccessControlPlugin.java:222)
	at de.deepamehta.plugins.accesscontrol.AccessControlPlugin.setupAccessControl(AccessControlPlugin.java:805)
	at de.deepamehta.plugins.accesscontrol.AccessControlPlugin.setupUserAccountAccessControl(AccessControlPlugin.java:793)
	at de.deepamehta.plugins.accesscontrol.AccessControlPlugin.postCreateTopic(AccessControlPlugin.java:410)
	at de.deepamehta.core.impl.CoreEvent$3.deliver(CoreEvent.java:53)
	at de.deepamehta.core.impl.EventManager.deliverEvent(EventManager.java:56)
	... 53 more
Caused by: java.lang.IllegalArgumentException: Null parameter, key=dm4.accesscontrol.creator, value=null
	at org.neo4j.kernel.impl.core.Primitive.setProperty(Primitive.java:327)
	at org.neo4j.kernel.impl.core.NodeImpl.setProperty(NodeImpl.java:52)
	at org.neo4j.kernel.impl.core.NodeProxy.setProperty(NodeProxy.java:130)
	at de.deepamehta.storage.neo4j.Neo4jStorage.storeAndIndexExactValue(Neo4jStorage.java:552)
	at de.deepamehta.storage.neo4j.Neo4jStorage.storeTopicProperty(Neo4jStorage.java:443)
	at de.deepamehta.core.impl.StorageDecorator.storeTopicProperty(StorageDecorator.java:581)
	at de.deepamehta.core.impl.AttachedTopic.setProperty(AttachedTopic.java:179)
	at de.deepamehta.plugins.accesscontrol.AccessControlPlugin.setCreator(AccessControlPlugin.java:218)
	... 58 more

I am looking forward to ship these new and partially long desired features to our end-users (and system administrators) now. Thanks for your support.

comment:14 Changed 7 years ago by Malte

To checkout latest development efforts find https://github.com/mukil/org.deepamehta-sign-on

To get sign-on features working one must comment the following 3 lines in current ACL-Plugin:

private String username(HttpSession session) {
        String username = (String) session.getAttribute("username");
        // if (username == null) {
            // throw new RuntimeException("Session data inconsistency: \"username\" attribute is missing");
        // }
        return username;
}

Could we skip this "consistency check" somehow, e.g. just for requests which have set a custom (to be defined) session attribute? As far as I can see, no new security related issue would be introduced by such a workaround (skipping the session consistency check once in a while).

comment:15 follow-up: ↓ 16 Changed 7 years ago by Malte

To wrap it up again, here are the 2 issues we face.

1.) How could we enable my plugin to receive the response coming back from the AP without removing the Session consistency check?
2.) How can I create a "User Account"-Topic for a non-existing user (while ClientState? is null) so that "User Account"-Topic remains editable for the user (he/she is set as Owner)?

Thanks for your help.

comment:16 in reply to: ↑ 15 ; follow-up: ↓ 17 Changed 7 years ago by jri

Replying to Malte:

1.) How could we enable my plugin to receive the response coming back from the AP without removing the Session consistency check?

Try to put the data which you hold in the session directly in a cookie instead. Don't use a session for that.

For the moment a DM session represents a logged in user. There can not be a session without a "username" attribute.

2.) How can I create a "User Account"-Topic for a non-existing user (while ClientState? is null) so that "User Account"-Topic remains editable for the user (he/she is set as Owner)?

For a user who logged in via Open ID you should not create a User Account topic.

You could look on the situation this way:
There are different Login Approaches. Each login approach is characterized by both:

  1. a logic that checks the user credentials (when the user tries to log in)
  2. a repository for storing user accounts (username and password)

Currently DM supports 2 Login Approaches (thanks to your plugin):

  • DM Login
  • Open ID

DM Login uses the User Account topics to store the user accounts.
Open ID uses its own approach to store its user accounts.

My point is: User Account topics are a property/feature only of the "DM Login" approach (the "repository" aspect mentioned above). They have no meaning to the Open ID login approach.

When you mix up these aspects various odd situations arise. E.g. what should be stored as the password in a User Account topic when the user uses hers Open ID account to log in? Keeping the password only in one location is just the point of Open ID.

=> So, do not create a User Account topic for users who log in via Open ID. Instead create a session and set the "username" attribute once the user logged in successfully. As far as I know DM will work perfectly fine in this case. E.g. when she creates a topic DM uses the session-username to store the topic's creator/owner information. This works because DM stores the creator/owner information as a topic property (in contrast to an association to an User Account topic). If you encounter any problems with this approach please let me know.

comment:17 in reply to: ↑ 16 Changed 7 years ago by jri

Replying to jri:

=> So, do not create a User Account topic for users who log in via Open ID. Instead create a session and set the "username" attribute once the user logged in successfully.

This would advance your plugin to the next level, but obviously is not the whole solution. When there are 2 users with the same username -- one using DM Login, the other Open ID -- DM could not distinguish the 2 identities.

That's where the concept described in comment:8 revives: we must formally differentiate between "User Identity" and "Authentication Provider". From my point of view this is the way to go when we want bring the Open ID plugin to production-level.

comment:18 Changed 7 years ago by Malte

Hey jri, thanks for documenting some of your insights from our open-id-discussion.

In the meanting I switched to using Cookies for authenticating/identifying the Login-Requesting-Client, but the jopenid-library crashes this way because when jopenid tries to authenticates the incoming request (step 6 or 7) it *relies* on an existing HttpSession? object attached to the HttpServletRequest?-Object passed into the

Authentication authentication = manager.getAuthentication(request, mac_key, alias);

But I could successfully work around that throug creating a session just before this method-call (and invalidating the session if auth-fails), since we already passed the sesssion-data-inconsistency check of DM. Now auth wiöll succeed if the client comes with a "Cookie" containing the correct key for the signed-payload (in the response). From a security-perspective storing the key on client-side and not indirectly via a session-id is a bad idea, but I guess you are aware of that. I don't like this solution, I still favor using a HttpSession? for authenticating the login-requesting-client.

Regarding your comments:

=> So, do not create a User Account topic for users who log in via Open ID. Instead create a session and set the "username" attribute once the user logged in successfully. As far as I know DM will work perfectly fine in this case.

I followed that path at it lead me to the follwing exception and a new problem.

The new problem now is, use-case 2 is not-supported anymore since I don't have a "User Account" with which I could associate the "OpenId? URL" with (needed for just login and not account-creation), but I guess you were not aware of that.

In other words: Not creating a "user account", unless we completely switch to "user-identities" (as you propose) will outdo the current login-feature of this plugin.

And here is the exception I've come about when not creating a "User Account"-Topic, after the user had successfull authenticated with the OpenId?-plugin and already has a "DM-HTTPSession" with the "OpenId? style username" but without a "User Account"-Topic.

SCHWERWIEGEND: A DeepaMehta resource method or event listener threw an exception resp. an error occurred. Mapping exception/error to response: 500 (Internal Server Error).
java.lang.RuntimeException: Jersey response filtering failed
	at de.deepamehta.core.impl.JerseyResponseFilter.filter(JerseyResponseFilter.java:67)
	at com.sun.jersey.server.impl.application.WebApplicationImpl._handleRequest(WebApplicationImpl.java:1432)
	at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1360)
	at com.sun.jersey.server.impl.application.WebApplicationImpl.handleRequest(WebApplicationImpl.java:1350)
	at com.sun.jersey.spi.container.servlet.WebComponent.service(WebComponent.java:416)
	at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:538)
	at com.sun.jersey.spi.container.servlet.ServletContainer.service(ServletContainer.java:716)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
	at org.apache.felix.http.base.internal.handler.ServletHandler.doHandle(ServletHandler.java:96)
	at org.apache.felix.http.base.internal.handler.ServletHandler.handle(ServletHandler.java:79)
	at org.apache.felix.http.base.internal.dispatch.ServletPipeline.handle(ServletPipeline.java:42)
	at org.apache.felix.http.base.internal.dispatch.InvocationFilterChain.doFilter(InvocationFilterChain.java:49)
	at org.apache.felix.http.base.internal.dispatch.HttpFilterChain.doFilter(HttpFilterChain.java:33)
	at org.apache.felix.http.base.internal.dispatch.FilterPipeline.dispatch(FilterPipeline.java:48)
	at org.apache.felix.http.base.internal.dispatch.Dispatcher.dispatch(Dispatcher.java:39)
	at org.apache.felix.http.base.internal.DispatcherServlet.service(DispatcherServlet.java:67)
	at javax.servlet.http.HttpServlet.service(HttpServlet.java:820)
	at org.mortbay.jetty.servlet.ServletHolder.handle(ServletHolder.java:511)
	at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:390)
	at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:182)
	at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:765)
	at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
	at org.mortbay.jetty.Server.handle(Server.java:326)
	at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:542)
	at org.mortbay.jetty.HttpConnection$RequestHandler.headerComplete(HttpConnection.java:926)
	at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:549)
	at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:212)
	at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:404)
	at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:410)
	at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:582)
Caused by: java.lang.RuntimeException: Processing event PRE_SEND_ASSOCIATION_TYPE by plugin "DeepaMehta 4 Access Control" failed
	at de.deepamehta.core.impl.EventManager.deliverEvent(EventManager.java:63)
	at de.deepamehta.core.impl.EventManager.fireEvent(EventManager.java:49)
	at de.deepamehta.core.impl.EmbeddedService.fireEvent(EmbeddedService.java:598)
	at de.deepamehta.core.impl.JerseyResponseFilter.firePreSend(JerseyResponseFilter.java:86)
	at de.deepamehta.core.impl.JerseyResponseFilter.firePreSendAssociationTypes(JerseyResponseFilter.java:122)
	at de.deepamehta.core.impl.JerseyResponseFilter.filter(JerseyResponseFilter.java:60)
	... 29 more
Caused by: java.lang.RuntimeException: Determining permission for association type "dm4.webclient.search_result_item" (id=552) failed (user "vandehoods@googlemail.com", operation=WRITE)
	at de.deepamehta.plugins.accesscontrol.AccessControlPlugin.hasPermission(AccessControlPlugin.java:847)
	at de.deepamehta.plugins.accesscontrol.AccessControlPlugin.getPermissions(AccessControlPlugin.java:820)
	at de.deepamehta.plugins.accesscontrol.AccessControlPlugin.preSendAssociationType(AccessControlPlugin.java:500)
	at de.deepamehta.core.impl.CoreEvent$17.deliver(CoreEvent.java:171)
	at de.deepamehta.core.impl.EventManager.deliverEvent(EventManager.java:56)
	... 34 more
Caused by: java.lang.RuntimeException: User "vandehoods@googlemail.com" does not exist
	at de.deepamehta.plugins.accesscontrol.AccessControlPlugin.getUsernameOrThrow(AccessControlPlugin.java:534)
	at de.deepamehta.plugins.accesscontrol.AccessControlPlugin.userIsMember(AccessControlPlugin.java:888)
	at de.deepamehta.plugins.accesscontrol.AccessControlPlugin.userOccupiesRole(AccessControlPlugin.java:866)
	at de.deepamehta.plugins.accesscontrol.AccessControlPlugin.hasPermission(AccessControlPlugin.java:839)
	... 38 more

So what do you think, how can we proceed?
As far as I can see, if I start to use "User Account"-Topics again (and if i am interpreting the exception above correclty), everything (both uses cases) should be fine with how I circumvented dm's session-data-inconsistency check, except that new user accounts do not have a password set (but that could be solved through generating some and set those).

Regarding your proposals, I completely agree that we should do it the right way, like you sketched out in comment:8, (especially in sight of a similiar TUB task), BUT:

  • when differentiating between "User Identity" and "Authentication Provider", please lets aim to give every user many APs to choose from when authenticating in front of DM
  • how do we want to solve preventing duplicate usernames (User Accounts impersonating Open Id Accounts) if you don't store the "Username" of a user at all? I guess, as you briefly pointed out, a "User Identity" MUST hold a "Username", otherwise that could not be unique.
  • and please keep in mind use-case 2 of this plugin when searching for solutions (as described in comment:13), for that an openId must be stored along with the username (though this could be provided by means of an extension by this plugin for a "User Identity"-Topic, but) maybe this is an attribute of a specific AP?

Thanks for your thoughts & Cheers!

Update: I added an explanation above the exception-block informing you about the state of the application when this exception is thrown.

Last edited 7 years ago by Malte (previous) (diff)

comment:19 follow-up: ↓ 20 Changed 7 years ago by Malte

From a security-perspective storing the key on client-side and not indirectly via a session-id is a bad idea, but I guess you are aware of that. I don't like this solution, I still favor using a HttpSession?? for authenticating the login-requesting-client.

Thanks for the phone-talk: Yes you're completely right, if we talk about an attacker observing unencrypted network traffic it doesn't matter much if the secret is carried directly in a Cookie or indirectly in a HttpSession?; either way an attacker could impersonate our user easily.

As far as I can see, if I start to use "User Account"-Topics again (and if i am interpreting the exception above correclty), everything (both uses cases) should be fine with how I circumvented dm's session-data-inconsistency check, except that new user accounts do not have a password set (but that could be solved through generating some and set those).

And here my assumption was wrong, currently I cannot create a user-account-topic via dms.createTopic(userAccount, ..)-call, this fails caused by "missing username" in (intermediary) session. I think this reads like the hen-egg problem mentionde in point 2 of comment:15

...
Caused by: java.lang.RuntimeException: Processing event de.deepamehta.core.impl.CoreEvent$4@3e0bbd1b by plugin "DeepaMehta 4 Access Control" failed
	at de.deepamehta.core.impl.EventManager.deliverEvent(EventManager.java:72)
	at de.deepamehta.core.impl.EventManager.fireEvent(EventManager.java:58)
	at de.deepamehta.core.impl.EmbeddedService.fireEvent(EmbeddedService.java:554)
	at de.deepamehta.core.impl.EmbeddedService.createAssociation(EmbeddedService.java:307)
	... 74 more
Caused by: java.lang.RuntimeException: Setting up access control for association 57890 (typeUri="dm4.core.aggregation") failed (association (id=57890, uri="", typeUri="dm4.core.aggregation", value="", composite={},
        topic role (roleTypeUri="dm4.core.parent", playerId=57886),
        topic role (roleTypeUri="dm4.core.child", playerId=1860)))
	at de.deepamehta.plugins.accesscontrol.AccessControlPlugin.setupDefaultAccessControl(AccessControlPlugin.java:807)
	at de.deepamehta.plugins.accesscontrol.AccessControlPlugin.postCreateAssociation(AccessControlPlugin.java:443)
	at de.deepamehta.core.impl.CoreEvent$4.deliver(CoreEvent.java:63)
	at de.deepamehta.core.impl.EventManager.deliverEvent(EventManager.java:65)
	... 77 more
Caused by: java.lang.RuntimeException: Session data inconsistency: "username" attribute is missing
	at de.deepamehta.plugins.accesscontrol.AccessControlPlugin.username(AccessControlPlugin.java:748)
	at de.deepamehta.plugins.accesscontrol.AccessControlPlugin.getUsername(AccessControlPlugin.java:194)
	at de.deepamehta.plugins.accesscontrol.AccessControlPlugin.setupDefaultAccessControl(AccessControlPlugin.java:793)
	... 80 more

Maybe it is best if we implement a solutions whic solves point 2) in comment:15 first, e.g. equipping the ACL-module with an apropriate (and public) createUserAccount()-method.

comment:20 in reply to: ↑ 19 ; follow-up: ↓ 22 Changed 7 years ago by jri

Replying to Malte:

[...] I cannot create a user-account-topic via dms.createTopic(userAccount, ..)-call, this fails caused by "missing username" in (intermediary) session.

Have you tried this:

  1. Create a session for your injected request (request.getSession())
  2. Set the username session attribute (session.setAttribute("username", username))
  3. Make the dms.createTopic() call

That is, you actually login the user *before* creating its User Account topic.

For the moment I can't see why this would fail.
(We're talking about step 7 on our paper sketch, when your Open ID plugin processes the /openid/response request, right?)

comment:21 Changed 7 years ago by jri

BTW: why do you say "intermediary" session?
Do you invalidate the session before calling dms.createTopic()?
You must not do so. That session is the *real* user session from the moment the positive response from the Open ID provider arrives.

Try logging that session's ID (session.getId()) and see if there is a browser cookie with that ID.

comment:22 in reply to: ↑ 20 ; follow-up: ↓ 23 Changed 7 years ago by jri

Replying to jri:

  1. Create a session for your injected request (request.getSession())
  2. Set the username session attribute (session.setAttribute("username", username))
  3. Make the dms.createTopic() call

I guess you've tried exactly that already (and not invalidated the session), right?

Meanwhile I can see why this would fail ("Session data inconsistency").
Indeed you create a session but, HYPOTHESIS: while processing this very request the session is not associated with it because the request contains no corresponding cookie. That is, when you call FOR TESTING request.getSession() twice in a row actually 2 session are created. The 2nd call does not return the session created with the first call (compared by session.getId()). Can you confirm that?

In that case you could/must add a cookie to the HttpServletRequest? manually. But for the moment it seems to me this is not supported by Servlet API.

In case you confirm the question above I've no solution for the moment.

comment:23 in reply to: ↑ 22 Changed 7 years ago by jri

Replying to jri:

Meanwhile I can see why this would fail ("Session data inconsistency").
Indeed you create a session but, HYPOTHESIS: while processing this very request the session is not associated with it because the request contains no corresponding cookie. That is, when you call FOR TESTING request.getSession() twice in a row actually 2 session are created. The 2nd call does not return the session created with the first call (compared by session.getId()). Can you confirm that?

Meanwhile I tried that myself and can NOT confirm that hypothesis.

So we're back to

Have you tried this:

  1. Create a session for your injected request (request.getSession())
  2. Set the username session attribute (session.setAttribute("username", username))
  3. Make the dms.createTopic() call

This is my current suggestion.

comment:24 Changed 7 years ago by Malte

So we're back to
Have you tried this:

  1. Create a session for your injected request (request.getSession())
  2. Set the username session attribute (session.setAttribute("username", username))
  3. Make the dms.createTopic() call

This is my current suggestion.

Yes, if I set the username in the session BEFORE the create call account-creation works fine. Somehow I couldn't come up with that on my own yesterday, :/ - and thank you very much for your support!

comment:25 Changed 7 years ago by Malte

  • Status changed from new to closed
  • Resolution set to worksforme

This plugin is basically functional but has some open issues which we are not going to tackle right now:

Source Code: https://github.com/mukil/org.deepamehta-sign-on

What works OK wit this OpenID is:

  • Creating a new DM-"User Account" via authenticating via your Google or Yahoo Account Todo: Let users choose their DM-Username before account creation (and thus prevent that there maybe user-account doublettes created, e.g. username@… and username@… come both along)) Todo: Set some insane password since DMs passwod login method is active for such a "User Account" in parallel, but the user has not to chose a password during this registration process.
  • Creating a proper DM user session, when the "User Account" has the correct OpenID (that one the AP returns) setup for the specific "User Account".

Open issues:

  • Everything as described in comment:8 is not on the current core-development roadmap
  • The jopenid-lib (though lightweight and more or less readable code) would need to be patched to be deployed IRL. If someone knows/finds a more robust one, the issues above should be set back on a current dev-roadmap.

I decided to not go down this (experimental) path any further by now. Instead I will bring forward #405 which was specifically designed for DMs current password login methods, current "User account" model (and which will solve our core issue of self-registration in a more simple way).

Note: See TracTickets for help on using tickets.