Skip to content
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

use universal Gitea OAuth configuration #1442

Merged
merged 2 commits into from
Oct 24, 2023
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 48 additions & 2 deletions src/shared/Core.Tests/GenericOAuthConfigTests.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using System;
using System.Collections.Generic;
using GitCredentialManager.Tests.Objects;
using Xunit;

Expand All @@ -9,7 +10,9 @@ public class GenericOAuthConfigTests
[Fact]
public void GenericOAuthConfig_TryGet_Valid_ReturnsTrue()
{
var remoteUri = new Uri("https://example.com");
var protocol = "https";
var host = "example.com";
var remoteUri = new Uri($"{protocol}://{host}");
const string expectedClientId = "115845b0-77f8-4c06-a3dc-7d277381fad1";
const string expectedClientSecret = "4D35385D9F24";
const string expectedUserName = "TEST_USER";
Expand Down Expand Up @@ -44,7 +47,12 @@ public void GenericOAuthConfig_TryGet_Valid_ReturnsTrue()
RemoteUri = remoteUri
};

bool result = GenericOAuthConfig.TryGet(trace, settings, remoteUri, out GenericOAuthConfig config);
var input = new InputArguments(new Dictionary<string, string> {
{"protocol", protocol},
{"host", host},
});

bool result = GenericOAuthConfig.TryGet(trace, settings, input, out GenericOAuthConfig config);

Assert.True(result);
Assert.Equal(expectedClientId, config.ClientId);
Expand All @@ -57,5 +65,43 @@ public void GenericOAuthConfig_TryGet_Valid_ReturnsTrue()
Assert.Equal(expectedUserName, config.DefaultUserName);
Assert.True(config.UseAuthHeader);
}

[Fact]
public void GenericOAuthConfig_TryGet_Gitea()
{
var protocol = "https";
var host = "example.com";
var remoteUri = new Uri($"{protocol}://{host}");
// https://docs.gitea.com/next/development/oauth2-provider?_highlight=oauth#pre-configured-applications
const string expectedClientId = "e90ee53c-94e2-48ac-9358-a874fb9e0662";
// https://docs.gitea.com/next/development/oauth2-provider?_highlight=oauth#endpoints
const string authzEndpoint = "/login/oauth/authorize";
const string tokenEndpoint = "/login/oauth/access_token";
string[] expectedScopes = Array.Empty<string>();
var expectedRedirectUri = new Uri("http://127.0.0.1");
var expectedAuthzEndpoint = new Uri(remoteUri, authzEndpoint);
var expectedTokenEndpoint = new Uri(remoteUri, tokenEndpoint);

var trace = new NullTrace();
var settings = new TestSettings
{
RemoteUri = remoteUri
};

var input = new InputArguments(new Dictionary<string, string> {
{"protocol", protocol},
{"host", host},
{"wwwauth", "Basic realm=\"Gitea\""}
});

bool result = GenericOAuthConfig.TryGet(trace, settings, input, out GenericOAuthConfig config);

Assert.True(result);
Assert.Equal(expectedClientId, config.ClientId);
Assert.Equal(expectedRedirectUri, config.RedirectUri);
Assert.Equal(expectedScopes, config.Scopes);
Assert.Equal(expectedAuthzEndpoint, config.Endpoints.AuthorizationEndpoint);
Assert.Equal(expectedTokenEndpoint, config.Endpoints.TokenEndpoint);
}
}
}
2 changes: 1 addition & 1 deletion src/shared/Core/GenericHostProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ public override async Task<ICredential> GenerateCredentialAsync(InputArguments i
// Cannot check WIA or OAuth support for non-HTTP based protocols
}
// Check for an OAuth configuration for this remote
else if (GenericOAuthConfig.TryGet(Context.Trace, Context.Settings, uri, out GenericOAuthConfig oauthConfig))
else if (GenericOAuthConfig.TryGet(Context.Trace, Context.Settings, input, out GenericOAuthConfig oauthConfig))
{
Context.Trace.WriteLine($"Found generic OAuth configuration for '{uri}':");
Context.Trace.WriteLine($"\tAuthzEndpoint = {oauthConfig.Endpoints.AuthorizationEndpoint}");
Expand Down
44 changes: 34 additions & 10 deletions src/shared/Core/GenericOAuthConfig.cs
Original file line number Diff line number Diff line change
@@ -1,32 +1,56 @@
using System;
using System.Collections.Generic;
using System.Linq;
using GitCredentialManager.Authentication.OAuth;

namespace GitCredentialManager
{
public class GenericOAuthConfig
{
public static bool TryGet(ITrace trace, ISettings settings, Uri remoteUri, out GenericOAuthConfig config)
public static bool TryGet(ITrace trace, ISettings settings, InputArguments input, out GenericOAuthConfig config)
{
config = new GenericOAuthConfig();
Uri authzEndpointUri = null;
Uri tokenEndpointUri = null;
var remoteUri = input.GetRemoteUri();

if (!settings.TryGetSetting(
if (input.WwwAuth.Any(x => x.Contains("Basic realm=\"Gitea\"")))
{
trace.WriteLine($"Using universal Gitea OAuth configuration");
// https://docs.gitea.com/next/development/oauth2-provider?_highlight=oauth#pre-configured-applications
config.ClientId = "e90ee53c-94e2-48ac-9358-a874fb9e0662";
// https://docs.gitea.com/next/development/oauth2-provider?_highlight=oauth#endpoints
authzEndpointUri = new Uri(remoteUri, "/login/oauth/authorize");
tokenEndpointUri = new Uri(remoteUri, "/login/oauth/access_token");
config.RedirectUri = new Uri("http://127.0.0.1");
}

if (settings.TryGetSetting(
Constants.EnvironmentVariables.OAuthAuthzEndpoint,
Constants.GitConfiguration.Credential.SectionName,
Constants.GitConfiguration.Credential.OAuthAuthzEndpoint,
out string authzEndpoint) ||
!Uri.TryCreate(remoteUri, authzEndpoint, out Uri authzEndpointUri))
out string authzEndpoint))
{
Uri.TryCreate(remoteUri, authzEndpoint, out authzEndpointUri);
}

if (authzEndpointUri == null)
{
trace.WriteLine($"Invalid OAuth configuration - missing/invalid authorize endpoint: {authzEndpoint}");
config = null;
return false;
}

if (!settings.TryGetSetting(
if (settings.TryGetSetting(
Constants.EnvironmentVariables.OAuthTokenEndpoint,
Constants.GitConfiguration.Credential.SectionName,
Constants.GitConfiguration.Credential.OAuthTokenEndpoint,
out string tokenEndpoint) ||
!Uri.TryCreate(remoteUri, tokenEndpoint, out Uri tokenEndpointUri))
out string tokenEndpoint))
{
Uri.TryCreate(remoteUri, tokenEndpoint, out tokenEndpointUri);
}

if (tokenEndpointUri == null)
{
trace.WriteLine($"Invalid OAuth configuration - missing/invalid token endpoint: {tokenEndpoint}");
config = null;
Expand Down Expand Up @@ -74,12 +98,12 @@ public static bool TryGet(ITrace trace, ISettings settings, Uri remoteUri, out G
Constants.EnvironmentVariables.OAuthRedirectUri,
Constants.GitConfiguration.Credential.SectionName,
Constants.GitConfiguration.Credential.OAuthRedirectUri,
out string redirectUrl) &&
Uri.TryCreate(redirectUrl, UriKind.Absolute, out Uri redirectUri))
out string redirectUrl) && Uri.TryCreate(redirectUrl, UriKind.Absolute, out Uri redirectUri))
{
config.RedirectUri = redirectUri;
}
else

if (config.RedirectUri == null)
{
trace.WriteLine($"Invalid OAuth configuration - missing/invalid redirect URI: {redirectUrl}");
config = null;
Expand Down