IdentityServer / IdentityServer3

OpenID Connect Provider and OAuth 2.0 Authorization Server Framework for ASP.NET 4.x/Katana
https://identityserver.github.io/Documentation/
Apache License 2.0
2.01k stars 763 forks source link

Started using MembershipReboot. IdentityServer now producing errors. #2567

Closed binarymist closed 8 years ago

binarymist commented 8 years ago

The setup we have is a collection of backend microservices, a middleware API (client) that makes a request to the IdentityServer.

The middleware API was working before I made changes to the AuthService and it hasn't been changed at all. The method that's failing is:

_tokenClient = new TokenClient(
                "https://identity.localtest.me:44334/connect/token",
                "clientid",
                "clientsecret");
            // Username and password args are substituted in here
            var req = _tokenClient.RequestResourceOwnerPasswordAsync("username", "password", "scope1, scope2, etc");

I've used most of https://github.com/IdentityServer/IdentityServer3.MembershipReboot in our AuthService.

Startup logs (Added these after submitting ticket, as may be of some use): 2016-02-14 13:41:08.877 +13:00 [Information] [MachineName:"mybox",ProcessId:9172,ThreadId:8,ThreadName:null] http://api.localtest.me:8083 2016-02-14 13:41:08.891 +13:00 [Information] [MachineName:"mybox",ProcessId:9172,ThreadId:8,ThreadName:null] Auth Service OWIN Self-Host 2016-02-14 13:41:09.242 +13:00 [Warning] AuthorizationCodeStore not configured - falling back to InMemory 2016-02-14 13:41:09.283 +13:00 [Warning] TokenHandleStore not configured - falling back to InMemory 2016-02-14 13:41:09.297 +13:00 [Warning] ConsentStore not configured - falling back to InMemory 2016-02-14 13:41:09.331 +13:00 [Warning] RefreshTokenStore not configured - falling back to InMemory 2016-02-14 13:41:09.618 +13:00 [Information] [MachineName:"mybox",ProcessId:9172,ThreadId:8,ThreadName:null] https://identity.localtest.me:44334

The errors being produced by serilog: 016-02-12 16:49:52.282 +13:00 [Information] Start token request 2016-02-12 16:49:52.308 +13:00 [Debug] Start client validation 2016-02-12 16:49:52.316 +13:00 [Debug] Start parsing for X.509 certificate 2016-02-12 16:49:52.322 +13:00 [Debug] client_id is not found in post body 2016-02-12 16:49:52.323 +13:00 [Debug] Start parsing for secret in post body 2016-02-12 16:49:52.334 +13:00 [Debug] No secret in post body found 2016-02-12 16:49:52.340 +13:00 [Debug] Start parsing Basic Authentication secret 2016-02-12 16:49:52.344 +13:00 [Debug] Parser found secret: "BasicAuthenticationSecretParser" 2016-02-12 16:49:52.350 +13:00 [Information] Secret id found: "MiddleWareClient" 2016-02-12 16:49:52.362 +13:00 [Debug] Secret validator success: "HashedSharedSecretValidator" 2016-02-12 16:49:52.370 +13:00 [Information] Client validation success 2016-02-12 16:49:52.383 +13:00 [Information] Start token request validation 2016-02-12 16:49:52.394 +13:00 [Information] Start password token request validation 2016-02-12 16:49:52.742 +13:00 [Error] User authentication failed: Invalid username or password { "ClientId": "MiddleWareClient", "ClientName": "Silicon on behalf of Carbon Client", "GrantType": "password", "Scopes": "offline_access MicroService1", "UserName": "bob", "AuthenticationContextReferenceClasses": [], "Raw": { "grant_type": "password", "username": "bob", "password": "**", "scope": "MicroService1 offline_access" } } 2016-02-12 16:49:52.758 +13:00 [Information] End token request 2016-02-12 16:49:52.772 +13:00 [Information] Returning error: invalid_grant

Please explain the: "client_id is not found in post body"? "No secret in post body found"?

It looks more like it's having a problem with the user name or password? Any idea why? We've been using the same username and password without an issues until we added the MembershipReboot code and database. If we use the SingleTenantOwinSystemWeb sample app against the same database, there is no issue. Any ideas why?

Thanks.

leastprivilege commented 8 years ago

have you debugged your user service (authenticate local) ?

binarymist commented 8 years ago

IdentityServer3.MembershipReboot.ValidateLocalCredentials makes a call to userAccountService.Authenticate with tenant of "default", correct username and password and the out account (null currently) and returns false. I can't step into Authenticate as it's binary.

So I'm struggling as to why it's telling us invalid username or password?

binarymist commented 8 years ago

In debugging the SingleTenantOwinSystemWeb, the LoginController's Index route calls: userAccountService.AuthenticateWithUsernameOrEmail Where as using the code from IdentityServer3.MembershipReboot calls: userAccountService.Authenticate At both these points the values of the arguments are the same, except that

Looking in UserAccountService, there is no such message as: "invalid username or password" "invalid username"

There is a "invalid password"

I tried using the UserAccountService source from BrockAllen.MembershipReboot, but it's different from when it was compiled for IdentityServer3.MembershipReboot.

When execution goes into UserAccountService.Authenticate, the tenant is "default", username and password as expected with the out account obviously set to null. Using the above mentioned UserAccountService source file, I can mouse over and obtain values for tenant, username, password and account. There is a statement:

if (String.IsNullOrWhiteSpace(password))

which evaluates to true, but the password variable is populated correctly. I also notice that String doesn't exist, but string does.

Then the following if statement evaluates to false:

if ((!Configuration.UsernamesUniqueAcrossTenants && String.IsNullOrWhiteSpace(tenant)) 
    || String.IsNullOrWhiteSpace(username) || String.IsNullOrWhiteSpace(password))
{
    failureCode = AuthenticationFailureCode.InvalidCredentials;
    return false;
}

So if this was the correct source, we'd still be OK.

Then interestingly

account = this.GetByUsername(tenant, username);

doesn't change the value of account which was explicitly set to null at the top of the same method "Authenticate". Now because the account is null, we get a failureCode of AuthenticationFailureCode.InvalidCredentials and false is returned from Authenticate.

When we debug into UserAccountService.GetByUsername, the

if (Configuration.UsernamesUniqueAcrossTenants)
{
    account = userRepository.GetByUsername(username);
}
else
{
    account = userRepository.GetByUsername(tenant, username);
}

Is skipped. Which means the GetByUsername is going to return a null account, which means we're not authenticated.

Other than removing the NuGet package and using the BrockAllen.MembershipReboot source I'm stuck as to what's going on in your binary. I've set serilogs LoggerConfiguration to MinimumLevel.Verbose as I see there are Verbose logs being posted, but none of these come through. Maybe they don't exist in the binary

binarymist commented 8 years ago

So swapped the BrockAllen NuGet packages for the source and I can see that EventBusUserAccountRepository.GetByUsername calls inner.GetByUsername. The following query

return Queryable.SingleOrDefault(x => 
                    tenant == x.Tenant &&
                    username == x.Username);

tenant is default and username is bob, same as is in the database table UserAccounts.

Then we go into DbContextUserAccountRepository.Queryable. Here we see the list of items is different to that in the SingleTenantOwinSystemWeb sample app. There is three extra fields: FirstName, LastName, Age. These fields don't exist in the database obviously

binarymist commented 8 years ago

So turned out that the IdentityServer3.MembershipReboot sample was expecting the three extra fields. Of course these fields are not created when you use the:

Sample projects: BrockAllen.MembershipReboot\samples\WebApiResourceOwner BrockAllen.MembershipReboot\samples\SingleTenantOwinSystemWeb

To create your database.

brockallen commented 8 years ago

An important distinction -- IdentityServer is separate from the identity management library you use to manage your user's identity and credentials.