Written by

Question Neil Thaiss · Feb 15, 2021

Can OAuth2 be used in a mirrored environment and what is the best practice?

Hi,

We a currently looking at a way of securing any future REST API's using OAuth2, where the Authorisation Server (OAuth2) and Resource Server would be on the same server.

However, as we have mirrored environment the Resource Server, and therefore the Authorisation Server, need work with a Virtual IP Address and be able to failover to either of the mirror member servers.

Is that possible with OAuth2 and if so what are the best practices for this?

Any advise or guidance much appreciated.

Thank you.

Product version: HealthShare 2020.1

Comments

McLean Cozine · Feb 16, 2021

Hi Neil,

You should be able to use OAuth 2.0 in a mirrored HealthShare environment just like you would in a non-mirrored one, I don't know of any difference in best practices. Assuming that you have set up your Mirror VIP properly the fact that you are using a virtual IP address shouldn't matter. Clients trying to connect to your server only need to know the VIP and HealthShare should take care of the rest.

As for the failover question, all of the necessary components of OAuth 2.0 are stored in the HealthShare database (access tokens, client configurations and definitions, server configurations and definitions) and therefore should be mirrored across machines. This means that OAuth, once set up, should be good to go in case of a failover.

Have you looked at Using OAuth 2.0 and OpenID Connect in the HealthShare docs? That chapter has instructions and some best practices for using OAuth with HealthShare that I think apply to mirrored and non-mirrored setups just the same.

Hope this helps,

McLean

0
Neil Thaiss  Feb 17, 2021 to McLean Cozine

Hi McLean,

Thank you for your reply, very useful.

With regards to failover and the necessary OAuth2 components this was my biggest concern as I had assumed these components where store in the %SYS database, which isn't mirrored.

However, you saying that they are stored in the HealthShare database made me think and I can now see that they there is a global mapping for the HSSYS database, which can, I'm sure, be mirrored.

I have gone through a lot of documentation, but is there any particular links, that relate to this specific area that you could pass on?

Thanks again.

Neil

0
McLean Cozine  Feb 17, 2021 to Neil Thaiss

Hi Neil,

I come bearing bad news, which is that it looks like I was mistaken and the OAuth objects are all stored in the %SYS database after all. I'll have to look into this a little more because I have to imagine that OAuth can be used in a mirrored environment.

Not that it's necessarily helpful if the mirroring doesn't get sorted out, but this is the link to the OAuth HealthShare documentation: https://docs.intersystems.com/healthconnectlatest/csp/docbook/DocBook.U… I was talking about.

I'll look into the mirroring question a bit more myself and see if I can find any better answers.

McLean

0
McLean Cozine  Feb 18, 2021 to Neil Thaiss

Neil,

I found this discussion on mirroring parts of the %SYS database: https://community.intersystems.com/post/how-sync-user-accounts-resource…. There are a few interesting ideas here that might be worth checking out. For instance, seeing if you can make an OAUTH database and map the contents of the OAuth client/server/etc. tables into it. Or seeing if you can create export and import methods for OAuth things. However, the fact that this is the most relevant discussion I could find seems to confirm that there's no accepted way to mirror parts of the %SYS database.

The Server Migration Guide (https://docs.intersystems.com/irislatest/csp/docbook/Doc.View.cls?KEY=A…) has notes on exporting from the IRISSYS database, though, it seems to focus on security settings, tasks, and custom items, none of which might be particularly helpful in this case. That said, it might be worth toying around with.

Sorry to have gotten your hopes up before, but hopefully some of this might help a little more.

McLean

0
Pravin Barton · Feb 19, 2021

Hi Neil,

Using OAuth2 in a mirrored environment would require some additional scripting to keep the configuration in sync between mirror members, since as you note it's stored in %SYS.

The Server Configuration on the auth server won't be changing much over time so I'd recommend writing an installation script that sets up all relevant configuration. Below are some snippets from an installation class I'm using on a Caché authorization server:

ClassMethod CreateServerConfiguration(pOrigNamespace As %String = "%SYS", Output interval As %Integer, Output server) As %Status
{
	Set server = ##class(OAuth2.Server.Configuration).Open(.tSC)
 	If $IsObject(server) {
	 	Set tSC = server.Delete()
	 	If $$$ISERR(tSC) Quit tSC
 	}
	
	Set interval = 3600

	Set server = ##class(OAuth2.Server.Configuration).%New()
	Set server.Description = "Single Sign-On"
	Set issuer = ##class(OAuth2.Endpoint).%New()
	Set issuer.Host = ..#IssuerHost
	Set issuer.Prefix = ..#IssuerPrefix
	Set server.IssuerEndpoint = issuer
	
	Set scopes = ##class(%ArrayOfDataTypes).%New()
	Do scopes.SetAt("OpenID Connect","openid")
	Do scopes.SetAt("E-mail Address","email")
	Do scopes.SetAt("User Profile","profile")
	// Add whatever other custom scopes you need
	Set server.SupportedScopes = scopes
	
	Set server.AllowUnsupportedScope = 0
	Set server.SupportedGrantTypes = "APCI"
	Set server.ReturnRefreshToken = ""
	Set server.AudRequired = 0
	
	Set server.CustomizationRoles = "%DB_CACHESYS,%Manager"
	Set server.CustomizationNamespace = pOrigNamespace
	Set server.AuthenticateClass = ..#CustomAuthenticateClassName
	Set server.ValidateUserClass = ..#CustomValidateClassName
	Set server.GenerateTokenClass = "%OAuth2.Server.JWT"
	
	Set server.AccessTokenInterval = interval
	Set server.RefreshTokenInterval = 3*interval
	Set server.AuthorizationCodeInterval = 120
	Set server.ServerCredentials = ..#ServerX509Name
	Set server.SigningAlgorithm = "RS512"
	Set server.KeyAlgorithm = ""
	Set server.EncryptionAlgorithm = ""
	Set server.SSLConfiguration = ..#SSLConfig
	
	Quit server.Save()
}

ClassMethod CreateServerDefinition(Output server) As %Status
{
	Set tIssuer = ..#EndpointRoot
	
	Set server = ##class(OAuth2.ServerDefinition).%OpenId("singleton")
	Set:'$IsObject(server) server = ##class(OAuth2.ServerDefinition).%New()
	Set server.IssuerEndpoint = tIssuer
	Set server.AuthorizationEndpoint = tIssuer_"/authorize"
	Set server.TokenEndpoint = tIssuer_"/token"
	Set server.UserinfoEndpoint = tIssuer_"/userinfo"
	Set server.IntrospectionEndpoint = tIssuer_"/introspection"
	Set server.RevocationEndpoint = tIssuer_"/revocation"
	Set server.ServerCredentials = ..#ServerX509Name
	Quit server.%Save()
}

The client descriptions are likely to change over time as new clients are registered. I think to keep these in sync between mirror members you'll need to regularly export the relevant globals directly from the primary, transport them to the secondary, and import them into the %SYS namespace. Below are some methods that do the export and import:

ClassMethod ExportClientConfiguration(pDestFile As %String) As %Status
{
	new $namespace
	set $namespace = "%SYS"
	for type = "D","I" {
		set tList("OAuth2.Server.Client"_type_".GBL") = ""
		set tList("OAuth2.Client.Metadata"_type_".GBL") = ""
	}
	set tSC = ##class(%File).CreateDirectoryChain(##class(%File).GetDirectory(pDestFile))
	return:$$$ISERR(tSC) tSC
	return $System.OBJ.Export(.tList,pDestFile,,.errorlog)
}

ClassMethod ImportClientConfiguration(pSourceFile As %String) As %Status
{
	new $namespace
	set $namespace = "%SYS"
	return $System.OBJ.Load(.pSourceFile,,.errorlog)
}

You could use a task to do this regularly on a short schedule.

0
Neil Thaiss  Feb 22, 2021 to Pravin Barton

Hi Pravin,

Thank you for your very detailed answer.

However, on investigation, I found that I didn't need any of this, as all the client and server configurations are stored in the HSSYS database, as are the access tokens, when they are created.

The %SYS namespace then contains a global mapping for OAuth2.* from the HSSYS database.

So, by mirroring the HSSYS database and setting the 'Customization namespace' to HSSYS in the OAuth2 server configuration, allows OAuth2 to continue to work after a failover.

Neil

0
Leon Wilson  Jan 19, 2022 to Neil Thaiss

Thank you Neil, I had the same issue and by mirroring the HSSYS database solved our issue. now we have the same ClientID and Secret between the DBs.

Much appreciated.

0