"ravick@cloudassert.com" 'in aktiviteleri

HealthySmilesAuthServerModule

https://localhost:44370/.well-known/openid-configuration { "issuer": "https://localhost:44370/", "authorization_endpoint": "https://localhost:44370/connect/authorize", "token_endpoint": "https://localhost:44370/connect/token", "introspection_endpoint": "https://localhost:44370/connect/introspect", "end_session_endpoint": "https://localhost:44370/connect/logout", "revocation_endpoint": "https://localhost:44370/connect/revocat", "userinfo_endpoint": "https://localhost:44370/connect/userinfo", "device_authorization_endpoint": "https://localhost:44370/device", "jwks_uri": "https://localhost:44370/.well-known/jwks", "grant_types_supported": [ "authorization_code", "implicit", "password", "client_credentials", "refresh_token", "urn:ietf:params:oauth:grant-type:device_code", "LinkLogin", "Impersonation" ], "response_types_supported": [ "code", "code id_token", "code id_token token", "code token", "id_token", "id_token token", "token", "none" ], "response_modes_supported": [ "form_post", "fragment", "query" ], "scopes_supported": [ "openid", "offline_access", "email", "profile", "phone", "roles", "address", "HealthySmiles" ], "claims_supported": [ "aud", "exp", "iat", "iss", "sub" ], "id_token_signing_alg_values_supported": [ "RS256" ], "code_challenge_methods_supported": [ "S256" ], "subject_types_supported": [ "public" ], "token_endpoint_auth_methods_supported": [ "client_secret_basic", "client_secret_post" ], "introspection_endpoint_auth_methods_supported": [ "client_secret_basic", "client_secret_post" ], "revocation_endpoint_auth_methods_supported": [ "client_secret_basic", "client_secret_post" ], "device_authorization_endpoint_auth_methods_supported": [ "client_secret_basic", "client_secret_post" ], "claims_parameter_supported": false, "request_parameter_supported": false, "request_uri_parameter_supported": false, "authorization_response_iss_parameter_supported": true }

Hello Anjali

I am getting bad request if I add scope Please see the code and the values passed in watch

Bad Request as response

<br>

Here is the token

eyJhbGciOiJSUzI1NiIsImtpZCI6IjkwM0E5OUVFRjI2NTJERDMyM0EwOUM2Q0NEMjM1ODU2MzVGOEUzQzAiLCJ4NXQiOiJrRHFaN3ZKbExkTWpvSnhzelNOWVZqWDQ0OEEiLCJ0eXAiOiJhdCtqd3QifQ.eyJvaV9wcnN0IjoiSGVhbHRoeVNtaWxlc19BdXRoIiwiY2xpZW50X2lkIjoiSGVhbHRoeVNtaWxlc19BdXRoIiwib2lfdGtuX2lkIjoiODc2MzlkYWEtYWQ1Zi0yNGUxLTliYTItM2EwZTM1OWYyNWJlIiwianRpIjoiYTkwNThkMDctMzFmMS00NzIwLWI1M2ItODcyNDEyODE0NzJmIiwiZXhwIjoxNjk3MTEwMzc1LCJpc3MiOiJodHRwczovL2xvY2FsaG9zdDo0NDM3MC8iLCJpYXQiOjE2OTcxMDY3NzV9.R6Fb44yErOlKj-FE_7CX-GrsmmDtv3BZgXCkWjeq02Mkyr3MEkB33eHydA6iEYblDPeqvHxmjQD3dgzJisTS9YTUe52qF8GwzE-PYIeUas37ejEdvA8JIs5VwMtxe4q_FOa2X9gffQihYtWdXd8I2doZVO-iYhp3l7VUHcTpQh_zcqP1bNonqv4ES5noHEizHb3ZPPTIFByAOoq-Eiu0fvXaZ_lOwNbiqHQNlShsPLk5ViEDVmkKGOrdbtwaLlyHh4H5LSKvUfq2oCfQilMoKeg0xg-_Ar-wDF_rH4topL-wgrJPGN2bVVXOffO66OM6lWT4vERHqgUEXBILUTaIpg

Upon further analysing the 401 issue I found inner exception as

As mentioned in the earlier post, I mentioned the scope as HealthySmiles and passing the scope as HealthySmiles too string token = await GetClientCredentialsTokenAsync($"{_configuration["AuthServer:Authority"]?.EnsureEndsWith('/')}connect/token" ?? string.Empty, "HealthySmiles_Auth", "1q2w3e*", new List<string> { "HealthySmiles" });

DB records

This is the scope I see in my table, and I have provided the same in the code as well.

Though I am able to create token, it fails with 401 error code when trying to create tenant using the API api/saas/tenants

I tried both "HealthySmiles" as well as commonScopes yet 401 unauthorized error.

Is there anything to add or remove in the permission list?

This is turning out to be a showstopper for the release :(

Yes, it got seeded successfully in database as well.

Here is the code

Seed Code

 //Auth Server Client
 var authClientId = configurationSection["Application_Auth:ClientId"];
 if (!authClientId.IsNullOrWhiteSpace())
 {
     var authClientIdRootUrl = configurationSection["Application_Auth:RootUrl"]?.TrimEnd('/');

     await CreateApplicationAsync(
         name: authClientId!,
         type: OpenIddictConstants.ClientTypes.Confidential,
         consentType: OpenIddictConstants.ConsentTypes.Implicit,
         displayName: "Auth Application",
         secret: configurationSection["Application_Auth:ClientSecret"] ?? "1q2w3e*",
         grantTypes: new List&lt;string&gt; { OpenIddictConstants.GrantTypes.ClientCredentials },
         scopes: new List&lt;string&gt; { "BookStore" },
         clientUri: authClientIdRootUrl,
         logoUri: "/images/clients/swagger.svg",
         permissions: new List&lt;string&gt;
         {
       "Saas.Tenants",
       "Saas.Tenants.Create",
       "Saas.Tenants.Update",
       "Saas.Tenants.ManageConnectionStrings",
       "Saas.Tenants.SetPassword",
       "Saas.Editions",
       "Saas.Editions.Create",
       "Saas.Editions.Update"
         }
     );
 }
 

appsettings.json

  "Application_Auth": {
    "ClientId": "Application_Auth",
    "ClientSecret": "1q2w3e*",
    "RootUrl": "https://localhost:44370"
  },
  

RegisterTeanantModel.cs

public class TempTenant
{
    public Guid id { get; set; }
}

public class RegisterTenantModel : RegisterModel
{
    private readonly IConfiguration _configuration;

    public RegisterTenantModel(IConfiguration configuration)
    {
        _configuration = configuration;
    }

    protected override async Task&lt;IdentityUser&gt; RegisterLocalUserAsync()
    {
        //ValidateModel();

        //var captchaResponse = string.Empty;
        //if (UseCaptcha)
        //{
        //    captchaResponse = HttpContext.Request.Form[RecaptchaValidatorBase.RecaptchaResponseKey];
        //}

        string token = await GetClientCredentialsTokenAsync($"{_configuration["AuthServer:Authority"]?.EnsureEndsWith('/')}connect/token" ?? string.Empty, "HealthySmiles_Auth", "1q2w3e*", new string[] { "BookStore" });


        var tenant = new
        {
            name = "demo",
            adminEmailAddress = "demo@demo.com",
            adminPassword = "Welcome1$"
        };

        var tenantId = await CreateTenant(token, JsonSerializer.Serialize(tenant));

        using (CurrentTenant.Change(tenantId))
        {
            var user = await UserManager.FindByEmailAsync("example@example.com");

            if (user == null)
            {
                throw new UserFriendlyException("UserNotFound");
            }
            user.SetPhoneNumber("9999999999", false);
            user.Name = "Demo";
            user.Surname = "Demo";
            await UserManager.UpdateAsync(user);

            return await UserManager.GetByIdAsync(user.Id);
        }
    }

    private async Task&lt;Guid?&gt; CreateTenant(string token, string body)
    {
        using (HttpClient client = new HttpClient())
        {
            var apiUrl = ""+"/api/saas/tenants";
            //var request = new HttpRequestMessage(HttpMethod.Post, $"{_configuration["RemoteServices:BaseUrl"]?.EnsureEndsWith('/')}api/saas/tenants");
            var request = new HttpRequestMessage(HttpMethod.Post, "https://localhost:44396/api/saas/tenants");
            request.Headers.Add("Authorization", $"Bearer {token}");

            request.Content = new StringContent(body, null, "application/json");
            var response = await client.SendAsync(request);
            response.EnsureSuccessStatusCode();
            var responseBody = await response.Content.ReadAsStringAsync();
            var responseDeserilized = JsonSerializer.Deserialize&lt;TempTenant&gt;(responseBody);

            return responseDeserilized?.id;
        }
    }
    private async Task&lt;string&gt; GetClientCredentialsTokenAsync(string tokenUrl, string clientId, string clientSecret, IEnumerable scopes = null)
    {
        // Create a HttpClient to send the request to the token endpoint
        using (HttpClient client = new HttpClient())
        {
            // Set the client credentials (client_id and client_secret) in the request headers
            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{clientId}:{clientSecret}")));

            // Prepare the request content for the token endpoint




            var requestContent = new List&lt;KeyValuePair&lt;string, string&gt;>() {

                new KeyValuePair&lt;string,string&gt;("grant_type", "client_credentials") };

            // Add scopes, if provided
            if (scopes != null)
            {
                requestContent.Add(new KeyValuePair&lt;string, string&gt;("scope", string.Join(" ", scopes)));
            }

            // Send the request to the token endpoint
            HttpResponseMessage response = await client.PostAsync(tokenUrl, new FormUrlEncodedContent(requestContent));

            // Check if the request was successful (status code 200)
            if (response.IsSuccessStatusCode)
            {
                // Read the response content (which should contain the access token)
                string responseContent = await response.Content.ReadAsStringAsync();

                // Deserialize the response to extract the access token
                dynamic responseData = JObject.Parse(responseContent);
                string accessToken = responseData.access_token;

                return accessToken;
            }
            else
            {
                // If the request was not successful, handle the error here
                // You might want to log or throw an exception
                throw new HttpRequestException($"Error getting access token. Status code: {response.StatusCode}");
            }
        }
    }

}
public class TenantResponse
{
    public Guid id { get; set; }
}

Hi Anjali,

Getting bad request when trying to get the token in GetClientCredentialsTokenAsync with scope. Here my request content

Without scope, token created successfully but since it doesn't have necessary scope, it fails with 401 when trying to create tenant. But we need scope and also CreateApplicationAsync checks for scope and throws error if not found.

Yes, we will have Captcha as well.

We are using Angular as front end. Do you have any code samples in Angular?

We are building a Saas product where an end user (as a tenant) can subscribe on their own. So, when they subscribe, we need to create a tenant and an admin user for them.

If it is as per the default flow, then the host user has to get the details in offline from the end user, login to the portal to create respective tenant on behalf of end user.

Any suggestions here?

Even if we write own appservice, still it has to be anonymous, and the flow will remain the same.

Also, we are not planning to expose all the Tenant APIs but only Create. Can you please share a code sample on how to override the existing permission of dependent module with [AllowAnonymous] attribute?

Hi

is the tenant onboarding done without login to host user?

Yes, it will be self-onboarding. How do I remove the Authentication for the APIs that are part of Tenant Management Module & Identity Module so that tenant can be onboarded without Host login.

I referred the link https://docs.abp.io/en/abp/latest/Authorization#changing-permission-definitions-of-a-depended-module . But when the permission is disabled, it prohibits the access to the API.

But in self-onboarding scenario, the API should be accessed anonymously.

22 kayıttan 11 ile 20 arası gösteriliyor.
Made with ❤️ on ABP v8.2.0-preview Updated on Mart 25, 2024, 15:11