Skip to content

Xtensive.Orm 7.2beta-1 Authentication issue #393

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
AnamikaDe8 opened this issue Jul 31, 2024 · 9 comments
Closed

Xtensive.Orm 7.2beta-1 Authentication issue #393

AnamikaDe8 opened this issue Jul 31, 2024 · 9 comments

Comments

@AnamikaDe8
Copy link

AnamikaDe8 commented Jul 31, 2024

@SergeiPavlov @alexyakunin @shuruev @AlexUstinov
We have a question.
Background

A .Net 4.7.2 web project with razor pages has been upgraded to .net 8.

  1. Servicestack 3 upgraded to ServiceStack 8
  2. Xtensive.Orm 5  7.2-Beta

We are facing an issue while trying to authenticate “auth/credentials” using IAuthenticationService Interface of Xtensive.orm.Security.

The IAuthenticationService.Authenticate returns null error

protected override IPrincipal Authenticate(string userNameOrEmail, string password)
{
var config = this.Session.GetSecurityConfiguration();
var service = this.Session.Services.Get(config.HashingServiceName);Error here 

 if (service == null)
     throw new InvalidOperationException(string.Format("Hashing service by name {0} is not found. Check Xtensive.Security configuration", config.HashingServiceName));

}
error
HashingServiceName = plain

We are guessing, the services are not getting registered properly.

We have used Domain Factory to initialize the DomainConfig and implemented a auth class from IAuthenticationService.

Could you please help.

@SergeiPavlov
Copy link
Contributor

SergeiPavlov commented Jul 31, 2024

@alex-kulakov ?

@alex-kulakov
Copy link
Contributor

Hello guys, thanks Sergei for pointing me to this.

@AnamikaDe8,

Let's check domain configuration types first. You need to make sure that types from Xtensive.Orm.Security assembly registered in DomainConfiguration.Types collection. If you have your own implementations of some interfaces from Xtensive.Orm.Security assembly then they should be registered too. You can actually see the types which are registered while debugging if you check DomainConfiguration instance and its property Types (you may have to click ResultView).

Please, check the types and tell me whether there are some types from Xtensive.Orm.Security assembly or maybe something missing that should be in registered types?

All session services (the ones in session.Services) are instantiated from types that are registered in domain configuration, if there is no type given in session.Services.Get<T>(seviceName) it will return null. This is why I asked to check the types

Another thing that bothers me is that "plain" hashing service appeared. If you don't use it and this happens then we probably have another issue. Plain hashing provider is default value. It can indicate that configuration section wasn't read from configuration file.

I don't know whether you are aware so I'll try to explain one particularity. Here's the thing,
.Net Framework and .NET (don't confuse them) have different approach to *.config files. .Net Framework kind of merges config files of all assemblies loaded into AppDomain into one single config and you can access sections of it by doing ConfigurationManager.GetSection(someSectionName) and no matter in what file the section was it will be there for the manager.

.NET don't act like that (at least last time I checked). It gets only config file of running executable. For example, NUnit runner which runs tests from some project will not have access to the project's App.config file. We faced this issue and had to load configurations explicitly in our unit-test projects. For example,

    private System.Configuration.Configuration GetConfigurationForTestAssembly()
    {
      // this gets true assembly configuration instead of config of nunit runner
      return GetType().Assembly.GetAssemblyConfiguration();
    }

and later on, load our configurations from the given instance

    protected DomainConfiguration LoadDomainConfiguration(string sectionName, string name)
    {
      return DomainConfiguration.Load(GetConfigurationForTestAssembly(), sectionName, name);
    }

I'm telling you this because it might be a part of problem and it's good to explain the root that causes it.

Thanks god, it is easy to workaround - you just need to load SecurityConfiguration and put it to Domain.Extensions collection after domain is built. For example, here is an extension method which may help you.

    public static SecurityConfiguration GetSecurityConfiguration(this Domain domain, System.Configuration.Configuration configuration)
    {
      var result = domain.Extensions.Get<SecurityConfiguration>();
      if (result == null) {
        result = SecurityConfiguration.Load(configuration);
        domain.Extensions.Set(result);
      }
      return result;
    }

I will probably put something similar to the Xtensive.Orm.Security project.

@AnamikaDe8
Copy link
Author

AnamikaDe8 commented Aug 2, 2024

Thanks @alex-kulakov For the reply.
Please see below the findings
The Types screenshot given below
Session.Domain.Types Instance post adding the custom class which implements IAuthenticationService
image

Session.Services
image

The Session.Authenticate calls the IauthenticationService.Authenticate. Upon filtering with the default authenticationService we get the below.
image

image
The iAuthenticationService when it is initializing, its name is "servicestack"
image

This is how the priovious project's web.config configuration. The same needs to done in .Net 8. But we do not have web.config but appsetting.json..Could you suggest
image

@alex-kulakov
Copy link
Contributor

So, the issue is inability to read config.

I'm not sure about how to correctly convert web.config to json config or how to connect old one it to asp.net application. Probably, I will have to re-think configuration loading in projects. I will consult with colleagues from web development department to not give you wrong answer, but unfortunately it will happen only on Monday.

If it blocks development process, I can suggest to temporary define domain and security configurations in code instead of configuration file.

For SecurityConfuguration, just create an instance and put it to the Extensions collection like so:

    public void InitializeSecurity(this Domain domain)
    {
        var secConfiguration = new SecurityConfiguration() {
            HashingServiceName = "servicestack",
            AuthenticationServiceName = "servicestack"
        };
        domain.Extensions.Set(secConfiguration);
    }

Do you need help with DomainConfiguration? Most of properties of it are self-explanatory, maybe DomainConfiguration.Types collection can confuse you, you need to use Register() method, not Add(), it has variant which gets Assembly as parameter.

@AnamikaDe8
Copy link
Author

Hi, We tried
public void InitializeSecurity(this Domain domain)
{
var secConfiguration = new SecurityConfiguration() {
HashingServiceName = "servicestack",
AuthenticationServiceName = "servicestack"
};
domain.Extensions.Set(secConfiguration);
}

But it seems the hashingservice and AuthenticationServiceName both are private Set. Hence cannot be set.

@alex-kulakov
Copy link
Contributor

alex-kulakov commented Aug 6, 2024

@AnamikaDe8,

Yes, You are right, sorry about that, I didn't notice.
I've been experimenting with new API for configurations and it seems that I will have to develop the whole process of reading configurations from scratch. Unfortunately, such easy configuration loading as DomainConfiguration.Load() no longer possible so it will take time. Thanks Microsoft for screwing backwards compatibility 😒

To not wait for this to be developed you may consider a workaround, it is quite ugly but it seems to work. If you don't mind having old-fashion config file next to .json one, I suggest following. Say, there is a Orm.config file with following content (I copied the configuration from your screenshot):

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <configSections>
    <section name="Xtensive.Orm" type="Xtensive.Orm.Configuration.Elements.ConfigurationSection, Xtensive.Orm"/>
    <section name="Xtensive.Orm.Security" type="Xtensive.Orm.Security.Configuration.ConfigurationSection, Xtensive.Orm.Security" />
  </configSections>
  <Xtensive.Orm>
    <domains>
      <!-- ConnectionString provider is set in DomainFactory and web.config/appsettings under DATAOBJECTS_ keys -->
      <domain name="Default" upgradeMode = "Validate"
              provider=""
              connectionString="">
        <types>
          <add assembly="Xtensive.Orm.Security" />
          <add assembly="Xtensive.Orm.Tracking" />
          <add assembly="Xtensive.Orm.BulkOperations" />
          <add assembly="Your.Assembly"/>
        </types>
        <sessions>
          <!-- Manual Activation (using session.Activate(){}) is not desired in this project-->
          <session name="Default" options="AutoActivation,AutoSaveChanges" isolationLevel="ReadCommitted" />
        </sessions>
      </domain>
    </domains>
  </Xtensive.Orm>
  <Xtensive.Orm.Security>
    <hashingService name="servicestack"/>
    <authenticationService name ="servicestack" />
  </Xtensive.Orm.Security>
</configuration>

To get configurations form this file you can do something like

ExeConfigurationFileMap configFileMap = new ExeConfigurationFileMap();
configFileMap.ExeConfigFilename = "Orm.config";
// ConfugurationUserLevel setting might change, though works on my machine
var configuration = System.Configuration.ConfigurationManager.OpenMappedExeConfiguration(configFileMap, ConfigurationUserLevel.None);
var domainConfiguration = DomainConfiguration.Load(configuration, "Default");// Default is name of desired domain configuration
var securityConfiguration = Xtensive.Orm.Security.Configuration.SecurityConfiguration.Load(configuration);
// later on you can put this securityConfiguration to Domain.Extensions collection.

Screenshot 2024-08-06 174223

@AnamikaDe8
Copy link
Author

AnamikaDe8 commented Aug 9, 2024

hi @alex-kulakov ,

We have successfully implemented the ORM.Config loading of configuration.Please note, an explicit set in extension is required for the loading. Earlier we loaded the Auth and Hash Service pro grammatically
image

Though, 7.2-Beta-1 being the only version which included the .NET 8 support, we cannot move our code to production with a Beta version of the package. Could we expect A final release with .Net 8 support any time soon.

it would be great, if the Configuration loading from appsettings.json implementation also is included.

Thanks in advance

@alex-kulakov
Copy link
Contributor

@AnamikaDe8,

I'm working on the loading of configurations form IConfigurationSection, it will support both json and xml (ConfigurationManager compatible format and newer version without xml attributes). Algorithms for extensions are already implemented, so I'm making proper testing and "polishing". Domain configuration, though, is different story, it is complicated so it will take some time - couple of weeks at least (if less time consumed, I will be happy).

Speaking of release, I need to publish 7.1.2 first, then there are pull-requests I plan to merge to master and, since some of them contain breaking changes and probably some issues may appear, next version from master will be 7.2-Beta-2, if everything is ok - RC with slight changes, if RC is OK then finally release version. Usually, I'd like pre-release versions to stay published for several weeks before next version to let possible issues pop. We definitely make it released 😉

Honestly, I had to make some bug fixes and other changes in our previous releases, some very important customers still use 6.0 so I have to make it live. This is why I was away from the version in master but after 7.1.2 will be releases all my attention will be on master version.

@alex-kulakov
Copy link
Contributor

@AnamikaDe8, I just created PR #397 which should make cases like yours a bit easier, at least no workaround will be required. after 7.1.2 release the changes will be merged to master and later released as next 7.2 version.

I believe I can close this issue now, can't I?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants