Identityserver4: Not authorized for resource owner flow?

Created on 30 Jan 2017  路  8Comments  路  Source: IdentityServer/IdentityServer4

Hi,

I am trying to add a custom validation to a solution using IdentityServer4 but when doing the call, this is how the validator looks like :

    public class ExternalValidator : IExtensionGrantValidator
    {
        public readonly IAnvandareRepository AnvandareRepository;
        public readonly ISettingsService SettingsService;

        public ExternalValidator(IAnvandareRepository anvandareRepository)
        {
            AnvandareRepository = anvandareRepository;
        }
        public string GrantType => "external";

        public async Task ValidateAsync(ExtensionGrantValidationContext context)
        {
            var HSAID  = context.Request.Raw["HSAID"];
            var tooken = context.Request.Raw["Token"];

            var ticketResult = await ValidateWeaddTicket(tooken);

            if (ticketResult.Item2)
            {
                var anvandare = await AnvandareRepository.GetAnvandareByExerntId(HSAID);
                if (anvandare != null)
                    context.Result = new GrantValidationResult(anvandare.person_id.ToString(), "pwd");
                return;
            }
            else
                context.Result.ErrorDescription = ticketResult.Item1;
        }
}

A break point withing this methid is triggered and I can see that the user is granted but then I get this :

      Start resource owner password token request validation
fail: IdentityServer4.Validation.TokenRequestValidator[0]
      ro.external.orbit not authorized for resource owner flow
fail: IdentityServer4.Validation.TokenRequestValidator[0]
      {
        "ClientId": "ro.external.my",
        "ClientName": "External client",
        "GrantType": "password",
        "Raw": {
          "grant_type": "password",
          "username": "4JFM",
          "password": "***REDACTED***"
        }
      }

This is how de config for the client looks like :

new Client
                {
                    ClientId = ClientTypes.ExternalToken,
                    ClientName = "External client",
                    AllowedGrantTypes = GrantTypes.List("external"),
                    AccessTokenType = AccessTokenType.Reference,
                    AllowOfflineAccess = true,
                    ClientSecrets = new List<Secret>
                    {
                        new Secret("secret.ro101.my".Sha256())
                    },
                    AllowedScopes = new List<string>
                    {
                        "my.wcf",
                    }

And this is the ExternToken on the client :

    public class ExternalToken : LoginTypeBase
    {
        public override string EndpointName => "DefaultNetHttp_RegularLogin";
        public override LoginType LoginType => LoginType.External;
        public override string ToString()
        {
            return LoginType.ToTranslatedString();
        }
        public override TokenClient GetTokenClient(string host, string port)
        {
            var url = $"http://{host}:{port}/connect/token";
            return new TokenClient(url, ClientTypes.ExternalToken, "secret.ro101.my");
        }
    }

I can麓t fint where to set the flow? How could this problem be solved?

question

Most helpful comment

Also curly braces exist for a reason :p

All 8 comments

you don't show the code where you make the actual token request with TokenClient.

Here you go :

_loginType = loginType;
            MyToken result = new MyToken();
            var tokenClient = await GetTokenClient();

            TokenResponse token;

            if (loginType.LoginType == Business.Entity.Enums.LoginType.External)
            {
                var userInfo = new
                {
                    HSAID = username,
                    Token = password
                };

                token = await tokenClient.RequestCustomGrantAsync("external", extra: userInfo);
            }
            if (loginType.LoginType == Business.Entity.Enums.LoginType.SmartCard)
                token = await tokenClient.RequestCustomGrantAsync("siths");
            else
                token = await tokenClient.RequestResourceOwnerPasswordAsync(username, password);

            if (token.IsError)
            {
                if(token.Exception != null)
                     throw token.Exception;
                throw new Exception("Could not connect to IdentityService : " + token.Error);
            }
            if (token == null || token.AccessToken == null)
                throw ValidationContainer.FromValidationKey(ValidationKey.Inloggning_AnvandarenNekad);
public override TokenClient GetTokenClient(string host, string port)
        {
            var url = $"http://{host}:{port}/connect/token";
            return new TokenClient(url, ClientTypes.ExternalToken, "secret.ro101.my");
        }
if (loginType.LoginType == Business.Entity.Enums.LoginType.SmartCard)
                token = await tokenClient.RequestCustomGrantAsync("siths");
            else
                token = await tokenClient.RequestResourceOwnerPasswordAsync(username, password);

Here is where I would debug - also you called the grant external in the pasted in code above..

Also curly braces exist for a reason :p

If I break on this line(in client) :

token = await tokenClient.RequestCustomGrantAsync("external", extra: userInfo);

I can see the following information on tokenClient :

Address : http://localhost:5000/connector/token
AuthenticationStyle : Basicauthentication
Client : System.Net.Http-HttpClient
ClientId : ro.external.my
ClientSecret : secret.ro101.my

When arriving in the ExternalValidator I can see the extra provided from the client(HSAID and Token).

The ClienctTypes.ExternalToken holds the "ro.external.my" so the clientID is matching on both client and server. Have also checked the secret.

Sorry do not understand what you are reffering to with curly braces.

My first post containing the log from IdentityServer was stating a clientId that was test1, this was just a small test I did, it is now change to the proper value and the correct fail looks like this(updated first post)

      Start resource owner password token request validation
fail: IdentityServer4.Validation.TokenRequestValidator[0]
      ro.external.orbit not authorized for resource owner flow
fail: IdentityServer4.Validation.TokenRequestValidator[0]
      {
        "ClientId": "ro.external.my",
        "ClientName": "External client",
        "GrantType": "password",
        "Raw": {
          "grant_type": "password",
          "username": "4JFM",
          "password": "***REDACTED***"
        }
      }

The fail says that it is not authorized for the resource owner flow, what exacly do not match?

I am not using any certificate? Could this be the problem? I have a simular setup that uses client and server certificate and this is working properly.

Found the problem! A "else if" was missing in the client that resulted in another login was fired right after with diffrent(wrong) data.

This thread has been automatically locked since there has not been any recent activity after it was closed. Please open a new issue for related bugs.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

wangkanai picture wangkanai  路  3Comments

chrisrestall picture chrisrestall  路  3Comments

leksim picture leksim  路  3Comments

not-good-with-usernames picture not-good-with-usernames  路  3Comments

agilenut picture agilenut  路  3Comments