Obtaining the client id during a resource owner password credentials flow

357 views
Skip to first unread message

Werner Strydom

unread,
Apr 30, 2012, 11:46:57 PM4/30/12
to dotnet...@googlegroups.com
Hello,

I'm a bit lost as to how to proceed.

In one application I obtain user credentials and call ExchangeUserCredentialForToken on the WebServerClient (which is correctly configured with client identifier, secret and endpoints). In my authorization server, IAuthorizationServerHost.IsResourceOwnerCredentialValid is called and returns true. The ClientIdentifier of the instance IAccessTokenRequest passed in is null. When IAuthorizationServerHost.IsAuthorizationValid is called the ClientIdentifier is null.  As a result, IsAuthorizationValid always returns null because it cannot find the respective client authorization. 

In essence, I'm looking for a way to deny a client that isn't authorized to obtain an access token using the resource owner password credentials flow.

Looking at the spec, it requires that I authenticate the client.  The question is: how do I do it with a manner compatible with the framework?

Thanks,
Werner

Andrew Arnott

unread,
May 1, 2012, 1:08:40 PM5/1/12
to dotnet...@googlegroups.com
Are you on v4.0.x?  If so, we have significant improvements in this area in the master branch slated for v4.1 that I invite you to check out.
--
You received this message because you are subscribed to the Google Groups "DotNetOpenAuth" group.
To view this discussion on the web visit https://groups.google.com/d/msg/dotnetopenid/-/cVlQ5Fb6yeQJ.
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.


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

Werner Strydom

unread,
May 1, 2012, 1:17:28 PM5/1/12
to dotnet...@googlegroups.com, dotnet...@googlegroups.com
I'm on 4.1.

Andrew Arnott

unread,
May 1, 2012, 1:52:04 PM5/1/12
to dotnet...@googlegroups.com
That's surprising.  I have a unit test that verifies that the authorization server can observe an authenticated client's resource owner grant and know what the client is for the IAuthorizationServerHost.CreateAccessToken call.  Are you saying that within your CreateAccessToken method that the ClientIdentifier property is null?

On Tuesday, May 1, 2012, Werner Strydom wrote:
I'm on 4.1.


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

Werner Strydom

unread,
May 1, 2012, 3:03:28 PM5/1/12
to dotnet...@googlegroups.com
It is null for IAuthorizationServerHost.IsResourceOwnerCredentialValid and IAuthorizationServerHost.IsAuthorizationValid. The latter then returns false. From the looks of things, the client id isn't passed to the server when calling WebServerClient.ExchangeUserCredentialForToken from the client.

My question is how to authenticate the client (using WebServerClient) before making a call to WebServerClient.ExchangeUserCredentialForToken.

Andrew Arnott

unread,
May 1, 2012, 7:46:48 PM5/1/12
to dotnet...@googlegroups.com
Ah, so if the client isn't sending an authenticated request then that would explain why your authorization server isn't seeing the client_id.  Authenticating the client for this grant type is just like other grant types: the WebServerClient instance must be prepped with the client id and secret.  Then it will include that credential with the resource owner grant token request.

Anonymous clients are allowed in the spec to request tokens in exchange for resource owner creds, but it's up to each auth server to decide whether to allow it or how to handle that case.  In my opinion, if the client already has the resource owner's credentials, they already "own" the user for better or worse.  So issuing an access token to even an anonymous client only really has two possible effects (that I can think of):
  1. The client now has a token that is resilient against resource owner password changes (that is elevation of privilege from just a password)
  2. An unguarded token endpoint willing to exchange resource owner creds for tokens may provide a way for brute force password guessing.
The anonymous client being null in IAuthorizationServerHost.IsAuthorizationValid is an interesting problem.  It has to be null, but in that case I don't know what basis you have to determine whether to consider the authorization valid.  It's probably not safe to issue a non-revokable token to the client given #1 above.  Barring any solutions to this problem, I may hardwire DNOA to reject resource owner cred grants from anonymous clients.

Thoughts?

 On Tuesday, May 1, 2012, Werner Strydom wrote:
It is null for IAuthorizationServerHost.IsResourceOwnerCredentialValid and IAuthorizationServerHost.IsAuthorizationValid.  The latter then returns false.  From the looks of things, the client id isn't passed to the server when calling WebServerClient.ExchangeUserCredentialForToken from the client.

My question is how to authenticate the client (using WebServerClient) before making a call to WebServerClient.ExchangeUserCredentialForToken.

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

Werner Strydom

unread,
May 1, 2012, 8:38:31 PM5/1/12
to dotnet...@googlegroups.com
Here is an integration test to verify what I'm trying to do:

[TestMethod]
public void ResourceOwnerGrant()
{
    var description = new AuthorizationServerDescription
                        {
                            AuthorizationEndpoint = new Uri("http://api.example.com/oauth/authorize"),
                            TokenEndpoint = new Uri("http://api.example.com/oauth/token"),
                        };
    var client = new WebServerClient(description, "Zwt68a7", "ZJ76opguW");
    var token = client.ExchangeUserCredentialForToken("bob", "Password1");
    Assert.IsNotNull(token);
    Assert.IsNotNull(token.AccessToken);
    Assert.IsTrue(token.AccessTokenExpirationUtc > DateTime.UtcNow.AddMinutes(1));
    Assert.IsTrue(token.AccessTokenIssueDateUtc <= DateTime.UtcNow);
}

In this scenario, the client identifier and secret is null when IsAuthorizationValid and IsResourceOwnerCredentialValid is called. If I still have to authenticate the client before calling ExchangeUserCredentialForToken, how would that look like? If that authentication scheme is up to me, how do I indicate to the WebServerClient instance that the client was previously authenticated.  For example, I can call GetClientAccessToken(), but have no idea what to do with the next response.

Forgive the confusion.  I'm pretty much using the most bleeding version of dotnetopenauth I can. Perhaps I'm assuming the feature works a certain way when you intended to have it work another way.

Werner

Werner Strydom

unread,
May 1, 2012, 8:39:01 PM5/1/12
to dotnet...@googlegroups.com
In my particular application I have no use for anonymous users or clients.  An untrusted client may obtain the credentials of a user, but the key security issue for me is whether that client can verify whether those credentials are correct and therefore gain access to the system.  In my case, only one website is allowed to do this.  However, I'm not sure whether a change to block anonymous clients would be of any benefit as I would have to validate the user and client whether they are null or not.   Perhaps its better left to the implementor.

Andrew Arnott

unread,
May 1, 2012, 8:41:33 PM5/1/12
to dotnet...@googlegroups.com
Hi Werner,

Exactly what version of DNOA are you using?  TeamCity's master branch is having trouble publishing nuget packages so if you're based on that you're actually relatively old for using this particular feature.

Your code looks fine.  The client authentication is done automatically just because you included the username and password in the WebServerClient constructor.

Including logs is always a potentially handy thing. :)


On Tuesday, May 1, 2012, Werner Strydom wrote:
--
You received this message because you are subscribed to the Google Groups "DotNetOpenAuth" group.
To view this discussion on the web visit https://groups.google.com/d/msg/dotnetopenid/-/rLiakmKB0XsJ.

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.

Werner Strydom

unread,
May 1, 2012, 8:57:54 PM5/1/12
to dotnet...@googlegroups.com, dotnet...@googlegroups.com
I'm using 4.1.0.12120. Expect the logs later tonight.

Werner Strydom

unread,
May 2, 2012, 2:21:21 PM5/2/12
to dotnet...@googlegroups.com
From the client process (aka MSTest method)

QTAgent32.exe Information: 0 : DotNetOpenAuth.Core, Version=4.1.0.0, Culture=neutral, PublicKeyToken=2780ccd10d57b246 (official)
QTAgent32.exe Information: 0 : Preparing to send AccessTokenResourceOwnerPasswordCredentialsRequest (2.0) message.
QTAgent32.exe Information: 0 : Sending AccessTokenResourceOwnerPasswordCredentialsRequest request.
QTAgent32.exe Information: 0 : HTTP POST http://api.example.com/oauth/token
QTAgent32.exe Information: 0 : The following required parameters were missing from the DotNetOpenAuth.OAuth2.Messages.AccessTokenFailedResponse message: {error,
}

QTAgent32.exe Information: 0 : Received AccessTokenSuccessResponse response.

Trace on the server:

w3wp.exe Information: 0 : Incoming HTTP request: POST http://api.example.com/oauth/token
w3wp.exe Information: 0 : The following required parameters were missing from the DotNetOpenAuth.OAuth2.AuthServer.Messages.AccessTokenRefreshRequestAS message: {refresh_token,
}
w3wp.exe Information: 0 : The following required parameters were missing from the DotNetOpenAuth.OAuth2.Messages.AccessTokenAuthorizationCodeRequestAS message: {code,
}
w3wp.exe Information: 0 : The following required parameters were missing from the DotNetOpenAuth.OAuth2.Messages.EndUserAuthorizationRequest message: {client_id,
response_type,
}
w3wp.exe Information: 0 : The following required parameters were missing from the DotNetOpenAuth.OAuth2.Messages.EndUserAuthorizationImplicitRequest message: {response_type,
client_id,
}
w3wp.exe Information: 0 : The following required parameters were missing from the DotNetOpenAuth.OAuth2.Messages.EndUserAuthorizationFailedResponse message: {error,
}
w3wp.exe Information: 0 : Incoming request received: AccessTokenResourceOwnerPasswordCredentialsRequest
w3wp.exe Information: 0 : Binding element DotNetOpenAuth.OAuth2.ChannelElements.TokenCodeSerializationBindingElement did not apply to message.
w3wp.exe Information: 0 : User `bob` successfully sign in
w3wp.exe Information: 0 : Binding element DotNetOpenAuth.OAuth2.ChannelElements.MessageValidationBindingElement applied to message.
w3wp.exe Information: 0 : Preparing to send AccessTokenSuccessResponse (2.0) message.
w3wp.exe Information: 0 : Binding element DotNetOpenAuth.OAuth2.ChannelElements.MessageValidationBindingElement did not apply to message.
w3wp.exe Information: 0 : Binding element DotNetOpenAuth.OAuth2.ChannelElements.TokenCodeSerializationBindingElement did not apply to message.
w3wp.exe Information: 0 : Sending message: AccessTokenSuccessResponse

There is an entry of mine stating that "bob" successfully signed in.

Werner

Andrew Arnott

unread,
May 11, 2012, 9:41:19 AM5/11/12
to dotnet...@googlegroups.com
Hi Werner,

Sorry to take so long to reply.

I'm not seeing all the detail from these logs that I expected.  For instance, the actual message content is missing.  It does seem like verbosity is turned up, but perhaps it can be even more verbose?  

--
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 view this discussion on the web visit https://groups.google.com/d/msg/dotnetopenid/-/2TXJST3-9fUJ.

Werner Strydom

unread,
May 11, 2012, 4:32:29 PM5/11/12
to dotnet...@googlegroups.com
No worries mate.

These were just the trace logs with log4net installed, but not configured.  I have never seen the actual message content in the trace outputs.  I can email you the fiddler outputs, if that helps. 

Werner

Andrew Arnott

unread,
May 11, 2012, 5:27:23 PM5/11/12
to dotnet...@googlegroups.com
Fiddler outputs would likely be helpful.  But full logs would probably be sufficient (or better, perhaps).  http://tinyurl.com/dnoalogs should tell you how.
--
You received this message because you are subscribed to the Google Groups "DotNetOpenAuth" group.
To view this discussion on the web visit https://groups.google.com/d/msg/dotnetopenid/-/Bu_6fnDaFoUJ.

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.


--

Werner Strydom

unread,
May 11, 2012, 5:32:19 PM5/11/12
to dotnet...@googlegroups.com
When I enable the rolling file appender, the file remains empty, even if I restart IIS.  Any ideas?

Werner Strydom

unread,
May 13, 2012, 5:35:02 AM5/13/12
to dotnet...@googlegroups.com
I'm unable to get log4net to work. There are no errors, but nothing additional is written to the debug view.

In the application start, I call log4net.Config.XmlConfigurator.Configure() and in the web.config I have the following:<log4net>

<appender name="TraceAppender" type="log4net.Appender.TraceAppender">

<layout type="log4net.Layout.PatternLayout">
<conversionPattern value="YYYY %date [%thread] %-5level %logger [%property{NDC}] - %message%newline" />
</layout>
</appender>  
<root>
<level value="ALL" />
<appender-ref ref="TraceAppender" />
</root>
<logger name="DotNetOpenAuth">
<level value="ALL" />    
</logger>

</log4net>

I restarted the applications, and only the existing stuff gets written to the trace view.  Giving up for the evening.

Werner
 

Werner Strydom

unread,
May 13, 2012, 6:09:05 PM5/13/12
to dotnet...@googlegroups.com
I started to build my own copy of DotNetOpenAuth and logging with log4net 1.2.11.0 still didn't work.  I had the necessary redirects in my assembly and didn't see any FileLoadExceptions as I usually saw before.  However, I replaced log4net that the DotNetOpenAuth references with 1.2.11.0 and logging started to work.  

Can we upgrade the version of log4net to 1.2.11.0?

Thanks,
Werner

Andrew Arnott

unread,
May 13, 2012, 7:50:45 PM5/13/12
to dotnet...@googlegroups.com
Please file a ticket for upgrading to the latest log4net.  
Runtime assembly binding redirect does work to unify log4net versions in the meantime -- many folks use it.

--
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 view this discussion on the web visit https://groups.google.com/d/msg/dotnetopenid/-/1YJ-zQ800iMJ.
Reply all
Reply to author
Forward
0 new messages