Skip to content

Conversation

@MikeAlhayek
Copy link
Member

No description provided.

@MikeAlhayek MikeAlhayek marked this pull request as draft October 14, 2025 18:14
@Piedone
Copy link
Member

Piedone commented Oct 14, 2025

Related: #16336.

@MikeAlhayek MikeAlhayek changed the title Add Azure Authentication for Redis Add Azure Authentication for Azure Services Oct 17, 2025
var protector = _dataProtectionProvider.CreateProtector(ProtectorName);

options.ConnectionString = protector.Unprotect(settings.ConnectionString);
var rawConnectionString = protector.Unprotect(settings.ConnectionString);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a tool/ui to generate the protected value?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes

@@ -0,0 +1,22 @@
namespace OrchardCore.Azure.Core;

public static class ConnectionStringHelper
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Use the standard DBConnectionStringBuilder instead.

}
else if (_providerOptions.Endpoint is not null)
{
var azureOptions = _optionsMonitor.Get(_providerOptions.CredentialName ?? AzureOptions.DefaultName);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO the azure module should provide a helper to get a TokenCredential or a Token from a name, or no name. The fallback and all logic should not be exposed and have to be repeated in all modules.

{
var redisOptions = _options.Get(_redisOptions.CredentialName ?? AzureOptions.DefaultName);

var scope = redisOptions.GetProperty<string>("Scope");
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should be in the Azure module, and be configured in the credentials.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am not follow you here


var requestContext = new TokenRequestContext([scope]);

var result = await credential.GetTokenAsync(requestContext, CancellationToken.None);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cf previous comment, this should be in the OC.Azure module.

@@ -0,0 +1,6 @@
namespace OrchardCore;

public interface ITokenProvider
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't recall how it's different than a TokenCredential.

ClientId = ClientId,
}),
AzureAuthenticationType.WorkloadIdentity => new WorkloadIdentityCredential(),
_ => null, // ApiKey and unsupported types
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should probably have a name too, and just throw if there is no name or an unknown one.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if a custom class needs to be created.

"DeploymentName": "<your-deployment-name>"
},
"Redis": {
"Alias": "my-default" // References another credentials entry (here, "my-default")
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not a fan of alias.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it can be removed now that we have credentialName in the settings of each service


!!! note
The credential named `Default` is a special case:
- It is automatically used whenever a service does not explicitly specify a credential name.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not what I explained, but you might have decided that on purpose.

* **Azure CLI (`AzureCli`)**
* **Default credentials (`Default`)**

> **Important:** For this module to work, the credential entry **must be named `Redis`** in your Azure credentials configuration.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't have to be. What's the reason? Why can't the options of the module define the name it needs to use?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"MyRedisInStagin"

@MikeAlhayek
Copy link
Member Author

@sebastienros I’d like to take this approach a step further by creating a dedicated Security module. This module would handle provider-specific credential management, with a UI similar to what I implemented in the Indexing module.

It would include a unified interface where users can manage their own credentials directly, while app owner can define provider-based credentials at the settings level (e.g., appsettings.json or environment variables)

I believe this approach will be more scalable and efficient. Initially, I’ll focus on Azure provider-based credentials, but the design will allow adding more providers over time.

In the future, we can extend this to include a Connection Strings UI that securely manages connection strings — potentially referencing credentials stored in the same module. For example, SMS or Email providers could use credentials or connection strings managed by the Security module.

This concept is similar to what I built in the AI Suite module, where I centralized connection string management for all providers, so much of that code can be reused here for the UI and data management.

Let me know what you think of this direction. I may leave the current PR as-is and start a new branch to keep the original intent intact and use it as a reference.

}
}
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"OrchardCore_Redis": {
  "Credentials": "MyRedisInStaging"
}

or

"OrchardCore_Redis": {
  "Credentials": "CommonAzureCredsInStaging"
}

@github-actions
Copy link
Contributor

This pull request has merge conflicts. Please resolve those before requesting a review.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants