web farm support for both OP and RP

78 views
Skip to first unread message

Dotan N.

unread,
Jan 24, 2011, 4:35:53 AM1/24/11
to dotnet...@googlegroups.com
Hi All,
I'm interested in knowing how DNOA supports web farm configuration out of the box.
Where the main issue is machines under load balancers (both RPs and in-house OPs).

From what I understand it doesn't support web farms, however, I'm trying to understand if there is any environment
configuration that can support it; such as load balancer in 'sticky IP' mode.

Can anyone think of such workarounds that doesn't include development of custom ApplicationStore/Nonce store?

And if none exist, perhaps an idea of the scope of supporting webfarms development wise?


Thanks

Øyvind Sean Kinsey

unread,
Jan 24, 2011, 5:59:49 AM1/24/11
to dotnet...@googlegroups.com
On Mon, Jan 24, 2011 at 10:35 AM, Dotan N. <dip...@gmail.com> wrote:
Hi All,
I'm interested in knowing how DNOA supports web farm configuration out of the box.
Where the main issue is machines under load balancers (both RPs and in-house OPs).

From what I understand it doesn't support web farms, however, I'm trying to understand if there is any environment
configuration that can support it; such as load balancer in 'sticky IP' mode.

DNOA fully supports web farms as it is itself not responsible for persistence (yes it does provide some default providers, but you can replace these). 
As long as your proxy sets the X-Forwarded-For header, and you use a shared storage, then everything should work. 
 

Can anyone think of such workarounds that doesn't include development of custom ApplicationStore/Nonce store?

You must _always_ implement a custom store - the one that ships is a volatile MemoryStore (which on purpose has been made to not compile outside the example project), and is not suitable for production.
 
Sean

Dotan N.

unread,
Jan 24, 2011, 6:14:13 AM1/24/11
to dotnet...@googlegroups.com
Hi Sean,
Assuming you are referring to CustomStore as not being ready for production -- that I do understand.
I'm also interested in the pitfalls of implementing such a custom store to be production ready, with regards to the security protocol itself (open ID). Can you share your insights?

Thanks

2011/1/24 Øyvind Sean Kinsey <oyv...@kinsey.no>
--
You received this message because you are subscribed to the Google Groups "DotNetOpenAuth" group.
To post to this group, send email to dotnet...@googlegroups.com.
To unsubscribe from this group, send email to dotnetopenid...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/dotnetopenid?hl=en.

Øyvind Sean Kinsey

unread,
Jan 24, 2011, 9:42:24 AM1/24/11
to dotnet...@googlegroups.com
On Mon, Jan 24, 2011 at 12:14 PM, Dotan N. <dip...@gmail.com> wrote:
Hi Sean,
Assuming you are referring to CustomStore as not being ready for production -- that I do understand.
I'm also interested in the pitfalls of implementing such a custom store to be production ready, with regards to the security protocol itself (open ID). Can you share your insights?

None of the built-in stores are production ready as one for production needs to store nonces, etc in a non-volatile, and in case of web farms, a shared storage.
The only implication security wise is that in case of the nonce-store being cleared, it opens for replay as an attack vector.

If this is relating to only the OpenID protocol, and not OAuth as DNOA also supports, then this isn't to much of an issue - having the nonce-store being wiped during a replay attack is highly unlikely.
But if you want to support webfarms where you have no way to provide 'sticky'ness, then a shared datastorage is essential for the sake of normal operations.

Sean



Dotan N.

unread,
Jan 24, 2011, 9:50:34 AM1/24/11
to dotnet...@googlegroups.com
So stickiness at the level of the OP will solve the problem ? (from tests just in, it does, just want to re-verify with others)
I may have asked before, are there any production ready database store or everyone implements their own?

2011/1/24 Øyvind Sean Kinsey <oyv...@kinsey.no>
On Mon, Jan 24, 2011 at 12:14 PM, Dotan N. <dip...@gmail.com> wrote:

Andrew Arnott

unread,
Jan 24, 2011, 10:30:36 AM1/24/11
to dotnetopenid
I'll adjust what Sean said slightly...

For OpenID scenarios, it isn't absolutely mandatory in all cases that you implement a custom store.  For OAuth it is mandatory (and its sample store is rigged to not compile outside the samples because it's a bad in production code).  But for OpenID, the standard in-memory store is sufficient for most (non web farm) RPs.  And in particular RPs that operate in "dumb" mode never have to provide a store at all since there is never anything to store.

For web farms, putting an RP in dumb mode is the easiest way to go.  But for RPs that require better performance or to leverage some of DNOA's enhanced security features, a custom store is required for web farms in order facilitate sharing state between the servers.  For OPs, a web farm must always implement a custom store because there is no "dumb mode" for OPs, and state must be shared in order to keep the protocol reliable and secure.

As far as how to implement a store securely, DNOA takes care of the security aspects except for exactly what an accurate implementation of the custom store interface would supply -- specifically nonce and association storage and lookup.  The documentation of that interface should help you understand what that interface should do.  And if you have specific questions we can certainly address those on this forum.

And as Sean said, as far as the load balancer goes, part of the OpenID protocol is to verify that the HTTP request that comes in is exactly what it should be, which load balances often mess with and cause the login to fail.  Sean  mentioned one of the HTTP headers that DNOA will look at that a load balancer can add that allows DNOA to figure out what the outside-facing HTTP request was in order for the login to succeed.

The RP store interface and the OP store interface both come with a default in-memory implementation built into the library -- again, not good for use in web farms and your implementation should be plugged in at runtime, or the RP should be put in "dumb" mode.  The CustomStore implementation is a sample designed, not to be used in production, but to give you an overall idea of how a database-driven store might look and behave.

--
Andrew Arnott
"I [may] not agree with what you have to say, but I'll defend to the death your right to say it." - S. G. Tallentyre

Dotan N.

unread,
Jan 24, 2011, 10:37:30 AM1/24/11
to dotnet...@googlegroups.com
beautifully explained, thanks guys.

Andrew Arnott

unread,
Jan 24, 2011, 10:46:07 AM1/24/11
to dotnetopenid
IP stickiness will not prevent an OP from having to implement the store interface.  Here's why:

The RP server sends a request to the OP to establish a shared secret with the OP.  The user then contacts the OP directly referencing the shared secret using a handle to that secret.  That means the OP has two requests from two different sources, yet they both must have access to the same shared state.  If I understand IP stickiness correctly, there is no guarantee that two independent sources will be routed to the same machine, therefore the shared state storage is still mandatory on the OP.

And yes, there is a production-ready, database implementation of the RP store (and the OP store would be very similar to this one).  It's available as part of the DNOA project template available for download from the VS Gallery.

--
Andrew Arnott
"I [may] not agree with what you have to say, but I'll defend to the death your right to say it." - S. G. Tallentyre


Øyvind Sean Kinsey

unread,
Jan 24, 2011, 11:13:36 AM1/24/11
to dotnet...@googlegroups.com
On Mon, Jan 24, 2011 at 4:46 PM, Andrew Arnott <andrew...@gmail.com> wrote:
..

If I understand IP stickiness correctly, there is no guarantee that two independent sources will be routed to the same machine, therefore the shared state storage is still mandatory on the OP.

Confirmed - IP based stickiness will not be able to correlate two requests using application layer data.
If one still does not want to take the extra work of getting shared state working, one could instruct the loadbalancer to sent openid related requests to a single server instead of distributing the load.

Dotan N.

unread,
Jan 25, 2011, 9:13:23 AM1/25/11
to dotnet...@googlegroups.com
sorry to re-iterate but my initial examinations show that stickiness may work.
i must also say that RP is stateless
lets illustrate the flow:

user goes to RP, RP then gets Xrds from Provider (anonymous mode)
RP then redirects me to OPX with all of the OpenID headers as prepared by
request.RedirectingResponse.AsActionResult()

so there was stickiness from RP to OP but i'm not sure how it affects the overall conversation.
[RP1 <- sticky -> OP2]

lets say that i'm getting OP1 now, (not OP2, that originally interacted with RP1).
at this stage I as a user look at the OP1 log in.
I'm working against OP1 and it has all of the session information passed to it.

now there is stickiness between user and OP
[USR <- sticky -> OP1]
since RP is stateless, OP1 has my session and can return to whatever RP with all of the state right?



2011/1/24 Øyvind Sean Kinsey <oyv...@kinsey.no>
On Mon, Jan 24, 2011 at 4:46 PM, Andrew Arnott <andrew...@gmail.com> wrote:

John Bradley

unread,
Jan 25, 2011, 9:23:01 AM1/25/11
to dotnet...@googlegroups.com
You need to check the nonce for replay.   The assertion itself is stateless.

Some RP with multiple servers rely on the time stamp in the nonce to reduce the window of replay across multiple hosts.
I don't recommend doing that,  checking the nonce for replay is an important security feature of openID.

John B.

John Bradley

unread,
Jan 25, 2011, 9:25:15 AM1/25/11
to dotnet...@googlegroups.com
PS there is also the issue of sharing the association between the RP servers.  However you can run in dumb mode to get around that.

On 2011-01-25, at 11:13 AM, Dotan N. wrote:

Andrew Arnott

unread,
Jan 25, 2011, 9:44:42 AM1/25/11
to dotnetopenid
Thanks, John.  Dotan did say that his RP is stateless.  So the web farm at the RP is easily checked off as done since there are no session requirements for OpenID on the RP side.  

Dotan, your experiments were lucky, that's all.  It's not reliable.  In your example, OP1 talks to the user.  The problem is that OP1 creates a private secret used to sign the assertion it sends to the user.  The user's browser then redirects back to the RP and hands the assertion to the RP.  The RP now calls OP2 to ask it to verify the assertion.  Without shared state, OP2 will reject the assertion rather than verifying it because it doesn't know OP1's private secret.

Thus, OPs in a web farm must share state.

And John, as long as OPs are sharing state (via DNOA's interface for that purpose) the nonce store will also be shared, taking care of replay attacks.

--
Andrew Arnott
"I [may] not agree with what you have to say, but I'll defend to the death your right to say it." - S. G. Tallentyre


John Bradley

unread,
Jan 25, 2011, 9:51:06 AM1/25/11
to dotnet...@googlegroups.com
That is if the OP is DNOA and properly set up.

In the general internet case the RP should check the nonce.  His case may be special.   I just don't want people to assume it is OK to always count on the OP to protect you against replay.

John

Dotan N.

unread,
Jan 25, 2011, 10:17:38 AM1/25/11
to dotnet...@googlegroups.com
Thanks Andrew,

" ...The RP now calls OP2 to ask it to verify the assertion. "

For some odd reason, I cannot locate where this call back occurs.

For example, in OpenIdRelyingParty, UserController, action Authenticate
all i'm seeing is response (being decoded from headers) and then:

switch (response.Status) {
... 
FormsAuthentication.SetAuthCookie(response.ClaimedIdentifier, false);
}

Once RP got back a positive assertion from the OP I can't see how it re-validates anything with it through calling back into it.

Perhaps i'm looking at an incorrect flow stage?

Andrew Arnott

unread,
Jan 25, 2011, 10:35:57 AM1/25/11
to dotnetopenid
Ah, DNOA is so simply subtle. :)

It's this line in the User controller's Authenticate action:
var response = openid.GetResponse();

That little gem there doesn't just read the incoming request.  It also validates the assertion that's coming in (necessarily so).  On a stateful RP that usually is a local signature check.  But on a stateless RP that means contacting the OP to ask it to verify the signature.

--
Andrew Arnott
"I [may] not agree with what you have to say, but I'll defend to the death your right to say it." - S. G. Tallentyre


Dotan N.

unread,
Jan 25, 2011, 10:37:57 AM1/25/11
to dotnet...@googlegroups.com
Thanks, makes sense!
Reply all
Reply to author
Forward
0 new messages