Aktivity „ten3systems“

OMG thank-you Salih! These are highly relevant and useful answers; in this way I could authenticate against the identity system and still leverage all the roles-based-permissions systems that are integrated with the project.

Brilliant, thank-you again. I had temporarily solved by building partial handlers that return the JSON results of the service calls I needed but obviously that is brittle and does not scale well. Your references are definitely the correct answer.

Cheers!

You are saying to use [AllowAnonymous] on my aggregate root entities GetListAsync(GetEntityInput input) (and other aggregate entities) service calls because allowing the world to access the calls would be more secure than using an authenticated principal?

I do not understand.

So overriding AbpAuthorizationService results in a call to AuthorizeAsync for an 'actually authenticated' user after the razor page (which shows CurrentUser.IsAuthenticated == true, rightly so) asks for a service method where the principal and resource are blank (but the requirements contains the permission specified in the service classes [Authorize(policyName)] attribute so the request fails. So that breaks logged in users but works for the guest user.

If I don't override the AbpAuthorizationService then being a regular logged in user now works and I can auth my "guest" user for the page load and even though I've "signed in" subsequent calls via ajax still fails (presumably because I'm not authorizing with Identity.Application scheme, although I tried that, it did not seem to work.

My thought now is I will have to allow the API controller a way to authorize the request separately as noted above. But perhaps with an OpenID application defined in the Administration => Open ID => Applications settings area. Then I'll have to figure out how to grab a token via that system and pass it to the JS client to use in headers of all $.AJAX requests

I can get middleware and a new "GuestCookies" scheme to SignInAsync my principal so that they are authorized for my single request to my landing page and theoretically that means I could set a cookie on the landing page also and use another middleware to do the same for the HttpApiControllerModule as well. I guess I was thinking that once I authorized my user they could be authorized for my service calls and be logged into the whole system but my cookie and the IdentityCookies are not the same (different scheme).

Further complication comes from the fact that followup requests are via AJAX to the controller module which seems to be hooked up to the identity system.

I guess the thing to do is

  1. use a new Authentication Scheme in the web project that has it's own custom handler IAuthenticationHandler, IAuthenticationSignInHandler
  2. on page load but before calling for data, .SignInAsync("CustomScheme", principal)
  3. set a custom cookie for 'auth' purposes (maybe containing my tenant id and other unique info)
  4. create a middleware for the HttpApiController module that looks for the cookie, verifies it, and authenticates it's own principal and uses the stored TenantID for data filter

And in this way I have custom principal for my scenario, have not polluted the identity store, utilized the existing permissions system, in the correct tenant, and can still consider the 'guest' a user for all other purposes such as AuditLogs etc.

Or I could create a single Guest user for each tenant and force sign him in on the landing page. Hahahahahasodfiiweifjaskldfjklas asfkldjfid

The guest user will not have an identity account. I want to 'fake' authorization at a landing page that only they will have the URL for. I looked at the AuthorizationService API it seems to only CHECK if the current principal is authorized, and does not seem to have any manual controls (unless I'm looking at the wrong one?)

namespace Volo.Abp.Authorization;

public interface IAbpAuthorizationService : IAuthorizationService, IServiceProviderAccessor

Yes! This was it. I configured options only in my .TestBase module (for tests) and my .WebHost module to run the module, and then in the .Web module of my downstream consuming projects. Also don't forget to [DependsOn] the storing module and the provider you are using.

Thank-you @maliming

Some additional intel: I spent some time to get the host project of my depended module to run so I could test whether the issue arise at the module level, or not. The depended module has Account Pro installed as well and does not exhibit the same issue and seems to be working as intended.

Let me know if I have implemented the re-usable module incorrectly or the consuming project incorrectly so that I can correct it. Thank-you

In addition to the configuration options from my initial post, it was necessary to add the following also:

    context.Services.Configure<AbpAccountOptions>(options =>
    {
        //For impersonation in Saas module
        options.TenantAdminUserName = "admin";
        options.ImpersonationTenantPermission = SaasHostPermissions.Tenants.Impersonation;

        //For impersonation in Identity module
        options.ImpersonationUserPermission = IdentityPermissions.Users.Impersonation;
    });

Your documentation should be changed to highlight the fact that the 5.0+ templates SUPPORT impersonation but that you must ENABLE it using the instructions in the document based on your template type. I was confused about it being "enabled" already as per the docs.

Yes, I did check the document. It says

Impersonation is enabled by defautl in ABP v5.0 and above.

I am using 6.0.2

HUZZAH! Thank-you @maliming you have provided the info I needed to solve this.

For future visitors trying to persist cryptographic key for IdentityServer4 in docker containers that are recreated at each deploy, the trick is to store a pfx cert file on the host that you load on app startup, along with a host mapping folder to store the generated keys (take a step further and encrypt the keys at rest).

I store the path and secret in ENV variables that are passed through docker-compose

Some code for you:

public class YourWebModule : AbpModule
    {
        public override void PreConfigureServices(ServiceConfigurationContext context)
        {
            context.Services.PreConfigure<AbpMvcDataAnnotationsLocalizationOptions>(options =>
            {
                PreConfigure<IIdentityServerBuilder>(builder =>
                {
                    ConfigureIdentityCertificate(context, builder);
                });

                options.AddAssemblyResource(
...your assemblies...
                );
            });
        }
        private static void ConfigureIdentityCertificate(ServiceConfigurationContext context, IIdentityServerBuilder builder)
        {
            var configuration = context.Services.GetConfiguration();
            var config = configuration.GetSection("Identity");
            var certSecret = config["Secret"];
            var certFilePath = config["CertificateStorePath"];

            if (string.IsNullOrEmpty(certSecret))
            {
                Console.WriteLine("ERROR: No secret specified for identity cert!");
                return;
            }
            
            if (string.IsNullOrEmpty(certFilePath) || !Directory.Exists(certFilePath))
            {
                Console.WriteLine("WARN: No specified CertificateStorePath or not found so falling back to content root.");
                certFilePath = context.Services.GetHostingEnvironment().ContentRootPath;
            }

            var certFile = Path.Combine(certFilePath, "cert.pfx");

            if (!File.Exists(certFile))
            {
                Console.WriteLine($"ERROR: Certificate file '{certFile}' not found on disk");
                return;
            }

            X509Certificate2 cert;
            try
            {
                cert = new X509Certificate2(
                    certFile,
                    certSecret,
                    X509KeyStorageFlags.MachineKeySet |
                    X509KeyStorageFlags.PersistKeySet |
                    X509KeyStorageFlags.Exportable
                );
            }
            catch (Exception exception)
            {
                Console.WriteLine($"ERROR: Could not parse the identity cert! Message={exception.Message}");
                return;
            }

            builder.AddSigningCredential(cert);
            context.Services.AddDataProtection()
                .PersistKeysToFileSystem(new DirectoryInfo(certFilePath));
        }

Create a cert using the following commands (*nix):

openssl genrsa 2048 openssl req -x509 -days 3650 -new -key privatekey.pem -out publickey.pem openssl pkcs12 -export -in publickey.pem -inkey privatekey.pem -out cert.pfx -password pass:$PASSWD <-- $PASSWD var in .sh script

Zobrazených 11 až 20 z 24 záznamov
Made with ❤️ on ABP v8.2.0-preview Updated on marca 25, 2024, 15:11