The PendingAuthenticationRequest in a web farm scenario

226 views
Skip to first unread message

terjeu

unread,
Mar 23, 2010, 4:47:23 AM3/23/10
to DotNetOpenAuth
Hi,

We have a web farm scenario that looks like this:

1) We have our OpenId Provider in a load-balanced environment, running
on several Windows servers.
2) The user visits a page at our RP and is redirected to one of the
load balanced OP servers for authentication.
3) The actual authentication can be provided by Google, which means
the user is redirected off of the OP server and to Google for
authentication.
4) The user is redirected back from Google to our OP pool of servers,
and here is where the fun begins:

If the user hits the same OP server as she was redirected to Google
from, there will be a ProviderEndpoint.PendingAuthenticationRequest
waiting for her when she returns (the pending request will be the one
that originated from the initial request made by the RP).

But what if she lands on one of the other OP servers, that has no
PendingRequest waiting for her?

I have implemented SQL Server Mode session state at the OP servers, so
I should be safe when it comes to session handling and sharing in
general, but it all boils down to this property of the
ProviderEndpoint class:

/// <summary>
/// Gets or sets an incoming OpenID authentication request that has
not yet been responded to.
/// </summary>
/// <remarks>
/// This request is stored in the ASP.NET Session state, so it will
survive across
/// redirects, postbacks, and transfers. This allows you to
authenticate the user
/// yourself, and confirm his/her desire to authenticate to the
relying party site
/// before responding to the relying party's authentication request.
/// </remarks>
public static IAuthenticationRequest PendingAuthenticationRequest {
get { return HttpContext.Current.Session[PendingRequestKey] as
IAuthenticationRequest; }
set { HttpContext.Current.Session[PendingRequestKey] = value; }
}

Does the fact that the PendingAuthenticationRequest is stored in
session, and therefore in SQL Server, mean that it can be restored
back from state at *any one* of the OP servers, and used to generate a
response back to the calling RP?

Can you see any (other) signs of this scenario violating the intended
use of the DNOA library?

To sum up our scenario:

RP (dnoa) => OP (dnoa) => Google

Regards,
Terje


terjeu

unread,
Mar 23, 2010, 4:51:43 AM3/23/10
to DotNetOpenAuth
I may also add that our OP is a hybrid/custom RP/OP server, so that it
function as a RP when communicating with Google, and as a OP when
responding to the original request from the RP.
All is based on DNOA.

Terje

Øyvind Sean Kinsey

unread,
Mar 23, 2010, 5:25:24 AM3/23/10
to dotnet...@googlegroups.com
That is correct. But if you want to handle this yourself in some other way (memcached or some other shared cache), then you can subclass the ProviderEndpoint control and implement your own state mechanism.
To unsubscribe from this group, send email to dotnetopenid+unsubscribegooglegroups.com or reply to this email with the words "REMOVE ME" as the subject.

Andrew Arnott

unread,
Mar 23, 2010, 9:42:00 AM3/23/10
to dotnetopenid
Since this particular member is static, subclassing won't let you override its behavior.  But no worries... you can totally ignore the member and store the request any way you want.  But since you've already implemented a SQL session store, I'd say you're already there and done.

What you must also do is implement the RP and OP application stores.  Since you already have a database this should be straightforward.  Just implement the IRelyingPartyApplicationStore and IProviderApplicationStore interfaces and pass these objects respectively into the OpenIdRelyingParty and the OpenIdProvider classes (which you can do via the web.config file if you prefer).  Technically you could just write a stateful Provider and leave the RP in stateless mode, but since you're all on the same set of hardware and database, it seems a shame to not go the rest of the way and make the whole thing stateful.

--
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


2010/3/23 Øyvind Sean Kinsey <oyv...@kinsey.no>

Øyvind Sean Kinsey

unread,
Mar 23, 2010, 9:43:44 AM3/23/10
to dotnet...@googlegroups.com
I was actually referring to override the methods currently using this member, and not the member itself, but I guess I should have made this more clear :)

Andrew Arnott

unread,
Mar 23, 2010, 9:47:41 AM3/23/10
to dotnetopenid
Ah, yes.  I suppose just ignoring the member doesn't prevent the session state from being stored, which may be undesirable if you're not using it and it's taking up space on your session server.  I should have made that a property on the control that can be turned off.

If this bothers anyone else, please file a bug on http://trac.dotnetopenauth.net/

terjeu

unread,
Mar 23, 2010, 2:00:33 PM3/23/10
to DotNetOpenAuth
First, thanks very much for the replies!
Questions inline.

On Mar 23, 2:47 pm, Andrew Arnott <andrewarn...@gmail.com> wrote:
> Ah, yes.  I suppose just ignoring the member doesn't prevent the session
> state from being stored, which may be undesirable if you're not using it and
> it's taking up space on your session server.  I should have made that a
> property on the control that can be turned off.

Can you please elaborate on what you mean when you say "if you're not
using it" (it=ProviderEndpoint.PendingAuthenticationRequest) ?
My guess is that you mean I don't use it anymore after storing it
somewhere else, like in my one state bag in session (=sql server)
Is that right? Because, afaik, I have to use the request/ pick it up
somewhere, to be able to create a response back to the RP, after being
redirected back to the OP from Google, right?

> 2010/3/23 Øyvind Sean Kinsey <oyv...@kinsey.no>
>
> > I was actually referring to override the methods currently using this
> > member, and not the member itself, but I guess I should have made this more
> > clear :)

The methods currently using this member
(=PendingAuthenticationRequest) are in my own classes at the OP, just
like the member is being used in the OpenIdProviderWebForms samples
(e.g. in Page_Load in decide.aspx.cs)
So I don't quite get what you mean when you say "override the methods
currently using this member".
Can you please elaborate on this? Did you mean storing the
pendingauthrequest in a state bag?

My goal is to be able to create a response back to the RP, on whatever
of the OP servers in the pool that's being called upon when redirected
back from Google, without loosing the context/state of the initial
request.

> >> What you must also do is implement the RP and OP application stores.
> >> Since you already have a database this should be straightforward.  Just
> >> implement the IRelyingPartyApplicationStore and IProviderApplicationStore
> >> interfaces and pass these objects respectively into the OpenIdRelyingParty
> >> and the OpenIdProvider classes (which you can do via the web.config file if
> >> you prefer).  Technically you could just write a stateful Provider and leave
> >> the RP in stateless mode, but since you're all on the same set of hardware
> >> and database, it seems a shame to not go the rest of the way and make the
> >> whole thing stateful.

I'm planning over time to implement the RP and OP application stores.
But for now, I was planning to let both the RP send stateless auth
requests to the OP, and let the OP (functioning also as an RP
remember) send stateless auth requests to Google.

Does that make sense, and do you see any problems with that in a LB
environment (until I get the app stores done)?

Regards,
Terje

Andrew Arnott

unread,
Mar 23, 2010, 2:49:40 PM3/23/10
to dotnetopenid
On Mar 23, 2:47 pm, Andrew Arnott <andrewarn...@gmail.com> wrote:
> Ah, yes.  I suppose just ignoring the member doesn't prevent the session
> state from being stored, which may be undesirable if you're not using it and
> it's taking up space on your session server.  I should have made that a
> property on the control that can be turned off.

Can you please elaborate on what you mean when you say "if you're not
using it" (it=ProviderEndpoint.PendingAuthenticationRequest) ?
My guess is that you mean I don't use it anymore after storing it
somewhere else, like in my one state bag in session (=sql server)
Is that right? Because, afaik, I have to use the request/ pick it up
somewhere, to be able to create a response back to the RP, after being
redirected back to the OP from Google, right?

Yes, you do have to have a drop-off and pick-up store of some type.  And the PendingAuthenticationRequest property is a great way to do it if you already have a session store, which you do.  I suggest you just use it as you are.  When I said "if you're not using it" that was in reference to the option you have to store the auth request in some other way than the default way, which is usually more trouble than it's worth unless you have highly customized requirements.
 

> 2010/3/23 Øyvind Sean Kinsey <oyv...@kinsey.no>
>
> > I was actually referring to override the methods currently using this
> > member, and not the member itself, but I guess I should have made this more
> > clear :)

The methods currently using this member
(=PendingAuthenticationRequest) are in my own classes at the OP, just
like the member is being used in the OpenIdProviderWebForms samples
(e.g. in Page_Load in decide.aspx.cs)
So I don't quite get what you mean when you say "override the methods
currently using this member".
Can you please elaborate on this? Did you mean storing the
pendingauthrequest in a state bag?

This property is set automatically by the ProviderEndpoint control when an authentication request comes in, so if you wanted to avoid that step because you intended to save the auth request in another way, you (currently) would have to either avoid using the control or derive your own type that overrides default behavior.  Using the control and simply removing uses of that property from your own code would be insufficient to keep it from being set automatically -- but again, I think all this is inconsequential to you since you already have it working.
 

My goal is to be able to create a response back to the RP, on whatever
of the OP servers in the pool that's being called upon when redirected
back from Google, without loosing the context/state of the initial
request.

I think you're either there, or nearly there.  Have you implemented those two state store interfaces I mentioned earlier? That's the only thing left.
 

> >> What you must also do is implement the RP and OP application stores.
> >> Since you already have a database this should be straightforward.  Just
> >> implement the IRelyingPartyApplicationStore and IProviderApplicationStore
> >> interfaces and pass these objects respectively into the OpenIdRelyingParty
> >> and the OpenIdProvider classes (which you can do via the web.config file if
> >> you prefer).  Technically you could just write a stateful Provider and leave
> >> the RP in stateless mode, but since you're all on the same set of hardware
> >> and database, it seems a shame to not go the rest of the way and make the
> >> whole thing stateful.

I'm planning over time to implement the RP and OP application stores.
But for now, I was planning to let both the RP send stateless auth
requests to the OP, and let the OP (functioning also as an RP
remember) send stateless auth requests to Google.

Does that make sense, and do you see any problems with that in a LB
environment (until I get the app stores done)?

The OpenIdProvider MUST have a state store in its function as a Provider.  You may be "getting away with it" currently because it has a default server-level application store implementation.  But in a web farm environment this is insufficient and will lead to erratic failures.  Your use of OpenIdRelyingParty can be stateless though.

terjeu

unread,
Mar 23, 2010, 3:32:20 PM3/23/10
to DotNetOpenAuth
> The OpenIdProvider MUST have a state store in its function as a Provider.
> You may be "getting away with it" currently because it has a default
> server-level application store implementation.  But in a web farm
> environment this is insufficient and will lead to erratic failures.  Your
> use of OpenIdRelyingParty can be stateless though.

Ok, I see that I'm getting confused here, because the mix of tasks and
state stores in my OP, as it also function as an RP...
Can we try to sum up?
1) Because the OP is a web farm, the
ProviderEnpoint.PendingAuthenticationRequest is safe across the farm
because of SQL Session Store..
2) But the RP part of the OP is *not* safe in its handling of
application stores before I create a database store for them aswell?
3) Our website functioning as a pure RP (also a web farm) is safe,
because it uses stateless communication with our OP farm, right?

Hmm, looking at my three statements I see that it's really confusing..

Regarding the application stores: In what situations are they
required? You say they are required for the OP to function in a web
farm. So far so good. But what about our pure RP which is also web-
farmed? Does that also need application stores, or is stateless
enough?

Do you happen to have a demo-implementation of the OP application
store to offer me? (I guess I would need to come up with the tables,
the stored procedures, and the ado.net logic to move data back and
forth, meaning a lot of writing code and testing, so a demo-app would
be most helpful :)

Regards,
Terje

Andrew Arnott

unread,
Mar 23, 2010, 5:55:14 PM3/23/10
to dotnetopenid
On Tue, Mar 23, 2010 at 12:32 PM, terjeu <terje.u...@gmail.com> wrote:
> The OpenIdProvider MUST have a state store in its function as a Provider.
> You may be "getting away with it" currently because it has a default
> server-level application store implementation.  But in a web farm
> environment this is insufficient and will lead to erratic failures.  Your
> use of OpenIdRelyingParty can be stateless though.

Ok, I see that I'm getting confused here, because the mix of tasks and
state stores in my OP, as it also function as an RP...
Can we try to sum up?
1) Because the OP is a web farm, the
ProviderEndpoint.PendingAuthenticationRequest is safe across the farm

because of SQL Session Store..

That's right.  But there is more state required for Providers than just for ProviderEndpoint.PendingAuthenticationRequest.  That one property uses session state, so that the individual authentication request is associated with an individual user across HTTP requests.  But there is an even more important bag of state that all Providers must support: application state, which stores association secrets and consumed nonces.  This application state can be just in server memory if there's just one server.  But when the Provider is on a web farm, the application state must be in a shared database as well.  DNOA accesses this database through the IProviderApplicationState interface which you must pass to the OpenIdProvider constructor, or through the web.config file. 
 
2) But the RP part of the OP is *not* safe in its handling of
application stores before I create a database store for them aswell?

RPs may not have any state at all.  This is true whether it's a pure RP or if its the RP role in an RP/OP hybrid.  In DotNetOpenAuth stateless mode is done with "new OpenIdRelyingParty(null)", or setting an ASP.NET control's Stateless property to true.  Note that passing null to the constructor is necessary -- calling the default constructor with no arguments is not stateless mode.

RPs perform better and are more secure when they operate in stateful mode, which in web farm environments requires a database backend and an implementation of IRelyingPartyApplicationStore that connects DNOA to that database.  Objects implementing this interface are passed to DNOA through the OpenIdRelyingParty(IRelyingPartyApplicationStore) constructor, or through the web.config file while using the default constructor.
 
3) Our website functioning as a pure RP (also a web farm) is safe,
because it uses stateless communication with our OP farm, right?

Yes, as I expounded on above, RPs can operate in stateless mode.  But remember that's not the default.  The default is lone-server-stateful mode.  So you need to either "opt-in" to stateless mode, or implement the shared database backend and use that.
 

Hmm, looking at my three statements I see that it's really confusing..

Regarding the application stores: In what situations are they
required? You say they are required for the OP to function in a web
farm. So far so good. But what about our pure RP which is also web-
farmed? Does that also need application stores, or is stateless
enough?

Hopefully the above clarifies this for you.  OPs always need application state that is shared across all servers on the farm, and they almost always (as is in your case) need session state as well.  RPs never need session state for OpenID, but having application state can improve their speed, functionality and security.

Do you happen to have a demo-implementation of the OP application
store to offer me? (I guess I would need to come up with the tables,
the stored procedures, and the ado.net logic to move data back and
forth, meaning a lot of writing code and testing, so a demo-app would
be most helpful :)

Yes, I have a sample custom RP store and associated ADO.NET schema.  And a custom OP store with associated ADO.NET schema.   This sample store still just uses memory instead of a database, but it was written to be very easy to just hook up a real database with minimal code changes.

terjeu

unread,
Mar 24, 2010, 12:23:43 PM3/24/10
to DotNetOpenAuth
Fantastic, Andrew!
That is so very well explained I recon you become a teacher/professor
or something! :)
I finally feel I've got kinda control of what I'm doing here, and I'm
well on my way at implementing the ProviderStore.
It's going very well, and I agree, it wasn't that hard! :)

Thanks very much!
Regards,
Terje

On Mar 23, 10:55 pm, Andrew Arnott <andrewarn...@gmail.com> wrote:


> On Tue, Mar 23, 2010 at 12:32 PM, terjeu <terje.ulves...@gmail.com> wrote:
> > > The OpenIdProvider MUST have a state store in its function as a Provider.
> > > You may be "getting away with it" currently because it has a default
> > > server-level application store implementation.  But in a web farm
> > > environment this is insufficient and will lead to erratic failures.  Your
> > > use of OpenIdRelyingParty can be stateless though.
>
> > Ok, I see that I'm getting confused here, because the mix of tasks and
> > state stores in my OP, as it also function as an RP...
> > Can we try to sum up?
> > 1) Because the OP is a web farm, the
> > ProviderEndpoint.PendingAuthenticationRequest is safe across the farm
> > because of SQL Session Store..
>
> That's right.  But there is more state required for Providers than just for

> ProviderEndpoint.PendingAuthenticationRequest.  That one property uses *
> session* state, so that the individual authentication request is associated


> with an individual user across HTTP requests.  But there is an even more

> important bag of state that all Providers must support: *application* state,


> which stores association secrets and consumed nonces.  This application

> state *can* be just in server memory if there's just one server.  But when


> the Provider is on a web farm, the application state must be in a shared
> database as well.  DNOA accesses this database through the
> IProviderApplicationState interface which you must pass to the
> OpenIdProvider constructor, or through the web.config file.
>
> > 2) But the RP part of the OP is *not* safe in its handling of
> > application stores before I create a database store for them aswell?
>

> RPs *may* not have any state at all.  This is true whether it's a pure RP or
> if its the RP role in an RP/OP hybrid.  In DotNetOpenAuth state*less* mode
> is done with "new OpenIdRelyingParty(*null*)", or setting an
> ASP.NETcontrol's Stateless property to true.  Note that passing null


> to the
> constructor is necessary -- calling the default constructor with no

> arguments is *not* stateless mode.
>
> RPs perform better and are more secure when they operate in state*ful* mode,

> store<http://github.com/aarnott/dotnetopenid/blob/v3.4/samples/OpenIdRelyin...>and
> associated ADO.NET
> schema<http://github.com/aarnott/dotnetopenid/blob/v3.4/samples/OpenIdRelyin...>.
> And a custom OP
> store<http://github.com/aarnott/dotnetopenid/blob/v3.4/samples/OpenIdProvid...>with
> associated ADO.NET
> schema<http://github.com/aarnott/dotnetopenid/blob/v3.4/samples/OpenIdProvid...>.

Andrew Arnott

unread,
Mar 24, 2010, 1:05:26 PM3/24/10
to dotnet...@googlegroups.com
I'm glad it helped.  One more common pitfall: be sure your database columns that store nonces, association handles and Claimed Identifiers are case sensitive.  (they should also have a unique constraint on them).  All of these are very commonly base64 encodings of binary nothingness.  Some databases have a default indexing of case insensitive, which will cause lots of bad things to happen including user account mixups or identity spoofing in the worst cases if you don't specifically make those columns case sensitive.

--
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


terjeu

unread,
Mar 24, 2010, 7:30:57 PM3/24/10
to DotNetOpenAuth
I've come across a problem trying to implement the
CustomProviderApplicationStore.
I get an error in the GetAssociation method, after getting the handle,
expires and privatedata from the database, and trying to call:

Association.Deserialize(bag.Handle, bag.Expires.ToUniversalTime(),
bag.Privatedata);

The error msg is:
[ArgumentOutOfRangeException: Specified argument was out of the range
of valid values.]
System.Diagnostics.Contracts.__ContractsRuntime.Requires(Boolean
condition, String message, String conditionText) +301
DotNetOpenAuth.OpenId.HmacShaAssociation..ctor(HmacSha
typeIdentity, String handle, Byte[] secret, TimeSpan totalLifeLength)
+184
DotNetOpenAuth.OpenId.HmacShaAssociation.Create(String handle,
Byte[] secret, TimeSpan totalLifeLength) +431
DotNetOpenAuth.OpenId.Association.Deserialize(String handle,
DateTime expiresUtc, Byte[] privateData) +308

[ArgumentException: The private data supplied does not meet the
requirements of any known Association type. Its length may be too
short, or it may have been corrupted.
Parameter name: privateData]
DotNetOpenAuth.OpenId.Association.Deserialize(String handle,
DateTime expiresUtc, Byte[] privateData) +365

DotNetOpenAuth.NRK.CustomProviderApplicationStore.GetAssociation(AssociationRelyingPartyType
distinguishingFactor, SecuritySettings securitySettings) in E:\Need\NRK
\NRKInnlogging\Main\Trunk\Source\OpenID src\DotNetOpenAuth.NRK
\CustomProviderApplicationStore.cs:52

DotNetOpenAuth.OpenId.ChannelElements.SigningBindingElement.GetDumbAssociationForSigning()
+30

DotNetOpenAuth.OpenId.ChannelElements.SigningBindingElement.GetAssociation(ITamperResistantOpenIdMessage
signedMessage) +383

DotNetOpenAuth.OpenId.ChannelElements.SigningBindingElement.ProcessOutgoingMessage(IProtocolMessage
message) +277

DotNetOpenAuth.Messaging.Channel.ProcessOutgoingMessage(IProtocolMessage
message) +319
DotNetOpenAuth.Messaging.Channel.PrepareResponse(IProtocolMessage
message) +176
DotNetOpenAuth.Messaging.Channel.Send(IProtocolMessage message)
+211
DotNetOpenAuth.OpenId.Provider.OpenIdProvider.SendResponse(IRequest
request) +346
DotNetOpenAuth.OpenId.Provider.ProviderEndpoint.SendResponse() +34
NRKRP.decide.Page_Load(Object sender, EventArgs e) in E:\Need\NRK
\NRKInnlogging\Main\Trunk\Source\NRK OpenID\NRK RP\decide.aspx.cs:67
System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp,
Object o, Object t, EventArgs e) +14
System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object
sender, EventArgs e) +35
System.Web.UI.Control.OnLoad(EventArgs e) +99
System.Web.UI.Control.LoadRecursive() +50
System.Web.UI.Page.ProcessRequestMain(Boolean
includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
+627

It's obviously the privatedata that's causing the problems.

Here is my method for GetAssociation:

public AssociationBag GetAssociation(string distinguishingFactor)
{
DbCommand selectCommand = null;
selectCommand = _db.GetStoredProcCommand("GetOpenIDAssociation");

_db.AddInParameter(selectCommand, "distinguishingFactor",
DbType.String, distinguishingFactor);

string handle = null;
DateTime expires = new DateTime();

long retval; // The bytes returned from GetBytes.
long startIndex = 0; // The starting position in the BLOB output
int bufferSize = 64; // Size of the BLOB buffer.
byte[] privatedata = new byte[bufferSize]; // The BLOB byte[]
buffer to be filled by GetBytes.

using (DbConnection conn = _db.CreateConnection())
{
conn.Open();
selectCommand.Connection = conn;

using (IDataReader dataReader =
selectCommand.ExecuteReader(CommandBehavior.SequentialAccess)) {
while (dataReader.Read()) {
handle = dataReader.GetString(0);
expires = dataReader.GetDateTime(1);

// Reset the starting byte for the new BLOB.
startIndex = 0;

// Read the bytes into outbyte[] and retain the number of bytes
returned.
retval = dataReader.GetBytes(2, startIndex, privatedata, 0,
bufferSize);
}
}
}

return new AssociationBag
{
Expires = expires,
Handle = handle,
Privatedata = privatedata
};
}

I have noticed that you have a field in the [OpenIDAssociation] table
called [PrivateDataLength]. I'm not using that now, and I guess that
is causing the trouble.

Can you please show me how I should code the dataReader.GetBytes to
proper handle the privatedata returned, and the privatedatalength
field? (I'm pretty sure the problem lies there, agree?)

Regards,
Terje

Andrew Arnott

unread,
Mar 24, 2010, 11:55:19 PM3/24/10
to dotnetopenid
Your diagnosis looks correct, terje.  The association's private data length is not fixed.  There are several possible sizes of association secrets.  You must persist the length and ensure that the byte[] buffer you return later is the same length.

--
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


terjeu

unread,
Mar 25, 2010, 10:58:28 AM3/25/10
to DotNetOpenAuth
Hi,

It looks like I've fixed the private data length problem, but I have
run into another problem regarding association expiry date:

My CustomProviderApplicationStore implements
IProviderApplicationStore. I'm implementing the
ClearExpiredAssociations method, but that method is never called. This
results in the [OpenIDAssociation] table being filled with expired
associations which in turn gives us an ArgumentOutOfRangeException
from the following code statement in the HmacShaAssociation
constructor:

Contract.Requires<ArgumentOutOfRangeException>(totalLifeLength >
TimeSpan.Zero);

Can I relate this exception to the fact that ClearExpiredAssociations
has not been called?

When is it appropriate to call the ClearExpiredAssociations method?

Exception stack trace:

2010-03-25 15:04:52,989 (GMT+1) [6] ERROR NRKRP.Global - An unhandled
exception was raised. Details follow:
System.Web.HttpUnhandledException: Exception of type
'System.Web.HttpUnhandledException' was thrown. --->
System.ArgumentException: The private data supplied does not meet the


requirements of any known Association type. Its length may be too
short, or it may have been corrupted.

Parameter name: privateData ---> System.ArgumentOutOfRangeException:


Specified argument was out of the range of valid values.

at
System.Diagnostics.Contracts.__ContractsRuntime.Requires[TException]
(Boolean condition, String message, String conditionText)
at DotNetOpenAuth.OpenId.HmacShaAssociation..ctor(HmacSha


typeIdentity, String handle, Byte[] secret, TimeSpan totalLifeLength)

in c:\BuildAgent\work\7ab20c0d948e028f\src\DotNetOpenAuth\OpenId
\HmacShaAssociation.cs:line 74
at DotNetOpenAuth.OpenId.HmacShaAssociation.Create(String handle,
Byte[] secret, TimeSpan totalLifeLength) in c:\BuildAgent\work
\7ab20c0d948e028f\src\DotNetOpenAuth\OpenId\HmacShaAssociation.cs:line
125
at DotNetOpenAuth.OpenId.Association.Deserialize(String handle,
DateTime expiresUtc, Byte[] privateData) in c:\BuildAgent\work
\7ab20c0d948e028f\src\DotNetOpenAuth\OpenId\Association.cs:line 171
--- End of inner exception stack trace ---
at DotNetOpenAuth.OpenId.Association.Deserialize(String handle,
DateTime expiresUtc, Byte[] privateData) in c:\BuildAgent\work
\7ab20c0d948e028f\src\DotNetOpenAuth\OpenId\Association.cs:line 173
at


DotNetOpenAuth.NRK.CustomProviderApplicationStore.GetAssociation(AssociationRelyingPartyType
distinguishingFactor, SecuritySettings securitySettings) in E:\Need\NRK
\NRKInnlogging\Main\Trunk\Source\OpenID src\DotNetOpenAuth.NRK

\CustomProviderApplicationStore.cs:line 49
at
DotNetOpenAuth.OpenId.ChannelElements.SigningBindingElement.GetDumbAssociationForSigning()
in c:\BuildAgent\work\7ab20c0d948e028f\src\DotNetOpenAuth\OpenId
\ChannelElements\SigningBindingElement.cs:line 406
at
DotNetOpenAuth.OpenId.ChannelElements.SigningBindingElement.GetAssociation(ITamperResistantOpenIdMessage
signedMessage) in c:\BuildAgent\work\7ab20c0d948e028f\src
\DotNetOpenAuth\OpenId\ChannelElements\SigningBindingElement.cs:line
325
at
DotNetOpenAuth.OpenId.ChannelElements.SigningBindingElement.ProcessOutgoingMessage(IProtocolMessage
message) in c:\BuildAgent\work\7ab20c0d948e028f\src\DotNetOpenAuth
\OpenId\ChannelElements\SigningBindingElement.cs:line 103
at
DotNetOpenAuth.Messaging.Channel.ProcessOutgoingMessage(IProtocolMessage
message) in c:\BuildAgent\work\7ab20c0d948e028f\src\DotNetOpenAuth
\Messaging\Channel.cs:line 763
at
DotNetOpenAuth.Messaging.Channel.PrepareResponse(IProtocolMessage
message) in c:\BuildAgent\work\7ab20c0d948e028f\src\DotNetOpenAuth
\Messaging\Channel.cs:line 244
at DotNetOpenAuth.Messaging.Channel.Send(IProtocolMessage message)
in c:\BuildAgent\work\7ab20c0d948e028f\src\DotNetOpenAuth\Messaging
\Channel.cs:line 231
at
DotNetOpenAuth.OpenId.Provider.OpenIdProvider.SendResponse(IRequest
request) in c:\BuildAgent\work\7ab20c0d948e028f\src\DotNetOpenAuth
\OpenId\Provider\OpenIdProvider.cs:line 289
at DotNetOpenAuth.OpenId.Provider.ProviderEndpoint.SendResponse()
in c:\BuildAgent\work\7ab20c0d948e028f\src\DotNetOpenAuth\OpenId
\Provider\ProviderEndpoint.cs:line 139
at NRKRP.decide.Page_Load(Object sender, EventArgs e) in E:\Need\NRK
\NRKInnlogging\Main\Trunk\Source\NRK OpenID\NRK RP\decide.aspx.cs:line
67
at System.Web.Util.CalliHelper.EventArgFunctionCaller(IntPtr fp,


Object o, Object t, EventArgs e)

at System.Web.Util.CalliEventHandlerDelegateProxy.Callback(Object
sender, EventArgs e)
at System.Web.UI.Control.OnLoad(EventArgs e)
at System.Web.UI.Control.LoadRecursive()
at System.Web.UI.Page.ProcessRequestMain(Boolean
includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
--- End of inner exception stack trace ---
at System.Web.UI.Page.HandleError(Exception e)
at System.Web.UI.Page.ProcessRequestMain(Boolean
includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
at System.Web.UI.Page.ProcessRequest(Boolean
includeStagesBeforeAsyncPoint, Boolean includeStagesAfterAsyncPoint)
at System.Web.UI.Page.ProcessRequest()
at System.Web.UI.Page.ProcessRequestWithNoAssert(HttpContext
context)
at System.Web.UI.Page.ProcessRequest(HttpContext context)
at ASP.decide_aspx.ProcessRequest(HttpContext context)
at
System.Web.HttpApplication.CallHandlerExecutionStep.System.Web.HttpApplication.IExecutionStep.Execute()
at System.Web.HttpApplication.ExecuteStep(IExecutionStep step,
Boolean& completedSynchronously)

Regards,
Terje

Andrew Arnott

unread,
Mar 25, 2010, 11:15:46 AM3/25/10
to dotnetopenid
Terjeu,

One of the responsibilities of an IProviderApplicationStore is to never return an expired association.  So when you're scanning your database for an association with a given handle, you must filter out expired associations before returning the result. 

ClearExpiredAssociations ... hmm.... it was supposed to be called periodically (every so many logins), but apparently that code is gone now.  Oops.  Thanks for pointing this out.  Well, as the documentation for that method says:

        /// <summary>
        /// Clears all expired associations from the store.
        /// </summary>
        /// <remarks>
        /// If another algorithm is in place to periodically clear out expired associations,
        /// this method call may be ignored.
        /// This should be done frequently enough to avoid a memory leak, but sparingly enough
        /// to not be a performance drain.
        /// </remarks>
        void ClearExpiredAssociations();

You can go ahead and forget about implementing that method and just use your own algorithm to periodically clear out expired nonces from your associations table.


--
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



--
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.


terjeu

unread,
Mar 25, 2010, 2:13:08 PM3/25/10
to DotNetOpenAuth
Okay,

I have one stored procedure that handles
GetAssociation(AssociationRelyingPartyType distinguishingFactor,
SecuritySettings securitySettings), called GetOpenIDAssociation (shown
under).

And I have one procedure that handles
GetAssociation(AssociationRelyingPartyType distinguishingFactor,
string handle), called GetUniqueOpenIDAssociation (shown under).

The GetUniqueOpenIDAssociation is only returning the association if it
hasn't expired, whereas GetOpenIDAssociation will return every
association (with matching distinguishingFactor) with expires in
descending order (*without* concerning wheter it has expired). Does
that make sense, or should both check for expiration?
(Is this a valid check for expiration: Expiration > getutcdate() ?)

Can you please check my procedures and see if they do the right thing?

ALTER PROCEDURE [dbo].[GetOpenIDAssociation]
@distinguishingFactor varchar(255)
AS
BEGIN
SET NOCOUNT ON;

SELECT AssociationHandle AS Handle, Expiration AS Expires,
PrivateDataLength, PrivateData
FROM OpenIDAssociation
WHERE (DistinguishingFactor = @distinguishingFactor)
ORDER BY Expires DESC

END

ALTER PROCEDURE [dbo].[GetUniqueOpenIDAssociation]
@distinguishingFactor varchar(255),
@handle varchar(255)
AS
BEGIN
SET NOCOUNT ON;

SELECT AssociationHandle AS Handle, Expiration AS Expires,
PrivateDataLength, PrivateData
FROM OpenIDAssociation
WHERE (DistinguishingFactor = @distinguishingFactor) AND
(AssociationHandle = @handle)
AND (Expiration > getutcdate())

END

Regards,
Terje

Øyvind Sean Kinsey

unread,
Mar 25, 2010, 2:19:27 PM3/25/10
to dotnet...@googlegroups.com
From the StandardRelyingPartyApplicationStore.cs

/// <summary>
/// Gets the best association (the one with the longest remaining life) for a given key.
/// </summary>
/// <param name="distinguishingFactor">The Uri (for relying parties) or Smart/Dumb (for Providers).</param>
/// <param name="securityRequirements">The security settings.</param>
/// <returns>
/// The requested association, or null if no unexpired <see cref="Association"/>s exist for the given key.
/// </returns>
public Association GetAssociation(Uri distinguishingFactor, SecuritySettings securityRequirements) {
return this.associationStore.GetAssociation(distinguishingFactor, securityRequirements);
}

An expired association (just as with expired tokens etc with OAuth) is for most uses the same as a non-existing one, and therefor it should not be returned.

Regards,
Terje

terjeu

unread,
Mar 25, 2010, 2:58:36 PM3/25/10
to DotNetOpenAuth
Thank you, Øyvind

I wasn't aware of those comments, but I see that they answer my
questions.
Thanks for telling me! :)

Terje

Reply all
Reply to author
Forward
0 new messages