feat: Enhancements in the way how OAuth2 providers can be configured (#1126)

* feat: Enhancements in the way how OAuth2 providers can be configured

Signed-off-by: Anatolii Bazko <abazko@redhat.com>

Co-authored-by: Serhii Leshchenko <sleshche@redhat.com>
pull/1134/head
Anatolii Bazko 2021-10-07 15:49:33 +03:00 committed by GitHub
parent 5e7dc085d4
commit 40487d56ce
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 354 additions and 77 deletions

View File

@ -153,9 +153,17 @@ const (
DefaultPostgresCpuLimit = "500m"
DefaultPostgresCpuRequest = "100m"
BitBucketOAuthConfigMountPath = "/che-conf/oauth/bitbucket"
BitBucketOAuthConfigPrivateKey = "private.key"
BitBucketOAuthConfigConsumerKey = "consumer.key"
BitBucketOAuthConfigMountPath = "/che-conf/oauth/bitbucket"
BitBucketOAuthConfigPrivateKeyFileName = "private.key"
BitBucketOAuthConfigConsumerKeyFileName = "consumer.key"
GitHubOAuthConfigMountPath = "/che-conf/oauth/github"
GitHubOAuthConfigClientIdFileName = "id"
GitHubOAuthConfigClientSecretFileName = "secret"
GitLabOAuthConfigMountPath = "/che-conf/oauth/gitlab"
GitLabOAuthConfigClientIdFileName = "id"
GitLabOAuthConfigClientSecretFileName = "secret"
)
func InitDefaults(defaultsPath string) {

View File

@ -308,15 +308,24 @@ func (s *Server) getCheConfigMapData() (cheEnv map[string]string, err error) {
addMap(cheEnv, s.deployContext.CheCluster.Spec.Server.CustomCheProperties)
// Update BitBucket endpoints
secrets, err := deploy.GetSecrets(s.deployContext, map[string]string{
err = setBitbucketEndpoints(s.deployContext, cheEnv)
if err != nil {
return nil, err
}
return cheEnv, nil
}
func setBitbucketEndpoints(deployContext *deploy.DeployContext, cheEnv map[string]string) error {
secrets, err := deploy.GetSecrets(deployContext, map[string]string{
deploy.KubernetesPartOfLabelKey: deploy.CheEclipseOrg,
deploy.KubernetesComponentLabelKey: deploy.OAuthScmConfiguration,
}, map[string]string{
deploy.CheEclipseOrgOAuthScmServer: "bitbucket",
})
if err != nil {
return nil, err
return err
} else if len(secrets) == 1 {
serverEndpoint := secrets[0].Annotations[deploy.CheEclipseOrgScmServerEndpoint]
endpoints, exists := cheEnv["CHE_INTEGRATION_BITBUCKET_SERVER__ENDPOINTS"]
@ -327,7 +336,7 @@ func (s *Server) getCheConfigMapData() (cheEnv map[string]string, err error) {
}
}
return cheEnv, nil
return nil
}
func GetCheConfigMapVersion(deployContext *deploy.DeployContext) string {

View File

@ -264,6 +264,16 @@ func (s Server) getDeploymentSpec() (*appsv1.Deployment, error) {
return nil, err
}
err = MountGitHubOAuthConfig(s.deployContext, deployment)
if err != nil {
return nil, err
}
err = MountGitLabOAuthConfig(s.deployContext, deployment)
if err != nil {
return nil, err
}
container := &deployment.Spec.Template.Spec.Containers[0]
chePostgresSecret := s.deployContext.CheCluster.Spec.Database.ChePostgresSecret
if len(chePostgresSecret) > 0 {
@ -374,7 +384,6 @@ func GetFullCheServerImageLink(checluster *orgv1.CheCluster) string {
}
func MountBitBucketOAuthConfig(deployContext *deploy.DeployContext, deployment *appsv1.Deployment) error {
// mount BitBucket configuration
secrets, err := deploy.GetSecrets(deployContext, map[string]string{
deploy.KubernetesPartOfLabelKey: deploy.CheEclipseOrg,
deploy.KubernetesComponentLabelKey: deploy.OAuthScmConfiguration,
@ -387,36 +396,120 @@ func MountBitBucketOAuthConfig(deployContext *deploy.DeployContext, deployment *
} else if len(secrets) > 1 {
return errors.New("More than 1 BitBucket OAuth configuration secrets found")
} else if len(secrets) == 1 {
// mount secrets
container := &deployment.Spec.Template.Spec.Containers[0]
deployment.Spec.Template.Spec.Volumes = append(deployment.Spec.Template.Spec.Volumes,
corev1.Volume{
Name: secrets[0].Name,
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: secrets[0].Name,
},
},
})
container.VolumeMounts = append(container.VolumeMounts,
corev1.VolumeMount{
Name: secrets[0].Name,
MountPath: deploy.BitBucketOAuthConfigMountPath,
})
// mount env
endpoint := secrets[0].Annotations[deploy.CheEclipseOrgScmServerEndpoint]
container.Env = append(container.Env, corev1.EnvVar{
Name: "CHE_OAUTH1_BITBUCKET_CONSUMERKEYPATH",
Value: deploy.BitBucketOAuthConfigMountPath + "/" + deploy.BitBucketOAuthConfigConsumerKey,
}, corev1.EnvVar{
Name: "CHE_OAUTH1_BITBUCKET_PRIVATEKEYPATH",
Value: deploy.BitBucketOAuthConfigMountPath + "/" + deploy.BitBucketOAuthConfigPrivateKey,
}, corev1.EnvVar{
Name: "CHE_OAUTH1_BITBUCKET_ENDPOINT",
Value: endpoint,
mountSecret(deployment, &secrets[0], deploy.BitBucketOAuthConfigMountPath)
mountEnv(deployment, []corev1.EnvVar{
{
Name: "CHE_OAUTH1_BITBUCKET_CONSUMERKEYPATH",
Value: deploy.BitBucketOAuthConfigMountPath + "/" + deploy.BitBucketOAuthConfigConsumerKeyFileName,
}, {
Name: "CHE_OAUTH1_BITBUCKET_PRIVATEKEYPATH",
Value: deploy.BitBucketOAuthConfigMountPath + "/" + deploy.BitBucketOAuthConfigPrivateKeyFileName,
},
})
endpoint := secrets[0].Annotations[deploy.CheEclipseOrgScmServerEndpoint]
if endpoint != "" {
mountEnv(deployment, []corev1.EnvVar{{
Name: "CHE_OAUTH1_BITBUCKET_ENDPOINT",
Value: endpoint,
}})
}
}
return nil
}
func MountGitHubOAuthConfig(deployContext *deploy.DeployContext, deployment *appsv1.Deployment) error {
secrets, err := deploy.GetSecrets(deployContext, map[string]string{
deploy.KubernetesPartOfLabelKey: deploy.CheEclipseOrg,
deploy.KubernetesComponentLabelKey: deploy.OAuthScmConfiguration,
}, map[string]string{
deploy.CheEclipseOrgOAuthScmServer: "github",
})
if err != nil {
return err
} else if len(secrets) > 1 {
return errors.New("More than 1 GitHub OAuth configuration secrets found")
} else if len(secrets) == 1 {
mountSecret(deployment, &secrets[0], deploy.GitHubOAuthConfigMountPath)
mountEnv(deployment, []corev1.EnvVar{
{
Name: "CHE_OAUTH2_GITHUB_CLIENTID__FILEPATH",
Value: deploy.GitHubOAuthConfigMountPath + "/" + deploy.GitHubOAuthConfigClientIdFileName,
}, {
Name: "CHE_OAUTH2_GITHUB_CLIENTSECRET__FILEPATH",
Value: deploy.GitHubOAuthConfigMountPath + "/" + deploy.GitHubOAuthConfigClientSecretFileName,
},
})
endpoint := secrets[0].Annotations[deploy.CheEclipseOrgScmServerEndpoint]
if endpoint != "" {
mountEnv(deployment, []corev1.EnvVar{{
Name: "CHE_INTEGRATION_GITHUB_SERVER__ENDPOINTS",
Value: endpoint,
}})
}
}
return nil
}
func MountGitLabOAuthConfig(deployContext *deploy.DeployContext, deployment *appsv1.Deployment) error {
secrets, err := deploy.GetSecrets(deployContext, map[string]string{
deploy.KubernetesPartOfLabelKey: deploy.CheEclipseOrg,
deploy.KubernetesComponentLabelKey: deploy.OAuthScmConfiguration,
}, map[string]string{
deploy.CheEclipseOrgOAuthScmServer: "gitlab",
})
if err != nil {
return err
} else if len(secrets) > 1 {
return errors.New("More than 1 GitLab OAuth configuration secrets found")
} else if len(secrets) == 1 {
mountSecret(deployment, &secrets[0], deploy.GitLabOAuthConfigMountPath)
mountEnv(deployment, []corev1.EnvVar{
{
Name: "CHE_OAUTH_GITLAB_CLIENTID__FILEPATH",
Value: deploy.GitLabOAuthConfigMountPath + "/" + deploy.GitLabOAuthConfigClientIdFileName,
}, {
Name: "CHE_OAUTH_GITLAB_CLIENTSECRET__FILEPATH",
Value: deploy.GitLabOAuthConfigMountPath + "/" + deploy.GitLabOAuthConfigClientSecretFileName,
},
})
endpoint := secrets[0].Annotations[deploy.CheEclipseOrgScmServerEndpoint]
if endpoint != "" {
mountEnv(deployment, []corev1.EnvVar{{
Name: "CHE_INTEGRATION_GITLAB_SERVER__ENDPOINTS",
Value: endpoint,
}})
}
}
return nil
}
func mountSecret(deployment *appsv1.Deployment, secret *corev1.Secret, mountPath string) {
container := &deployment.Spec.Template.Spec.Containers[0]
deployment.Spec.Template.Spec.Volumes = append(deployment.Spec.Template.Spec.Volumes,
corev1.Volume{
Name: secret.Name,
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: secret.Name,
},
},
})
container.VolumeMounts = append(container.VolumeMounts,
corev1.VolumeMount{
Name: secret.Name,
MountPath: mountPath,
})
}
func mountEnv(deployment *appsv1.Deployment, envVar []corev1.EnvVar) {
container := &deployment.Spec.Template.Spec.Containers[0]
container.Env = append(container.Env, envVar...)
}

View File

@ -13,10 +13,9 @@ package server
import (
"os"
"reflect"
"github.com/eclipse-che/che-operator/pkg/util"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"
"github.com/eclipse-che/che-operator/pkg/deploy"
@ -119,7 +118,6 @@ func TestMountBitBucketOAuthEnvVar(t *testing.T) {
type testCase struct {
name string
initObjects []runtime.Object
cheCluster *orgv1.CheCluster
expectedConsumerKeyPathEnv corev1.EnvVar
expectedPrivateKeyPathEnv corev1.EnvVar
expectedEndpointEnv corev1.EnvVar
@ -145,7 +143,7 @@ func TestMountBitBucketOAuthEnvVar(t *testing.T) {
},
Annotations: map[string]string{
"che.eclipse.org/oauth-scm-server": "bitbucket",
"che.eclipse.org/scm-server-endpoint": "bitbucket_endpoint",
"che.eclipse.org/scm-server-endpoint": "endpoint",
},
},
Data: map[string][]byte{
@ -154,11 +152,6 @@ func TestMountBitBucketOAuthEnvVar(t *testing.T) {
},
},
},
cheCluster: &orgv1.CheCluster{
ObjectMeta: metav1.ObjectMeta{
Namespace: "eclipse-che",
},
},
expectedConsumerKeyPathEnv: corev1.EnvVar{
Name: "CHE_OAUTH1_BITBUCKET_CONSUMERKEYPATH",
Value: "/che-conf/oauth/bitbucket/consumer.key",
@ -169,7 +162,7 @@ func TestMountBitBucketOAuthEnvVar(t *testing.T) {
},
expectedEndpointEnv: corev1.EnvVar{
Name: "CHE_OAUTH1_BITBUCKET_ENDPOINT",
Value: "bitbucket_endpoint",
Value: "endpoint",
},
expectedVolume: corev1.Volume{
Name: "github-oauth-config",
@ -188,51 +181,225 @@ func TestMountBitBucketOAuthEnvVar(t *testing.T) {
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
logf.SetLogger(zap.New(zap.WriteTo(os.Stdout), zap.UseDevMode(true)))
orgv1.SchemeBuilder.AddToScheme(scheme.Scheme)
testCase.initObjects = append(testCase.initObjects)
cli := fake.NewFakeClientWithScheme(scheme.Scheme, testCase.initObjects...)
deployContext := &deploy.DeployContext{
CheCluster: testCase.cheCluster,
ClusterAPI: deploy.ClusterAPI{
Client: cli,
Scheme: scheme.Scheme,
},
Proxy: &deploy.Proxy{},
}
deployContext := deploy.GetTestDeployContext(nil, testCase.initObjects)
server := NewServer(deployContext)
deployment, err := server.getDeploymentSpec()
if err != nil {
t.Fatalf("Error creating deployment: %v", err)
}
assert.Nil(t, err, "Unexpected error occurred %v", err)
container := &deployment.Spec.Template.Spec.Containers[0]
env := util.FindEnv(container.Env, "CHE_OAUTH1_BITBUCKET_CONSUMERKEYPATH")
if !reflect.DeepEqual(testCase.expectedConsumerKeyPathEnv, *env) {
t.Errorf("Expected Env and Env returned from API server differ (-want, +got): %v", cmp.Diff(testCase.expectedConsumerKeyPathEnv, env))
}
assert.NotNil(t, env)
assert.Equal(t, testCase.expectedConsumerKeyPathEnv, *env)
env = util.FindEnv(container.Env, "CHE_OAUTH1_BITBUCKET_PRIVATEKEYPATH")
if !reflect.DeepEqual(testCase.expectedPrivateKeyPathEnv, *env) {
t.Errorf("Expected Env and Env returned from API server differ (-want, +got): %v", cmp.Diff(testCase.expectedPrivateKeyPathEnv, env))
}
assert.NotNil(t, env)
assert.Equal(t, testCase.expectedPrivateKeyPathEnv, *env)
env = util.FindEnv(container.Env, "CHE_OAUTH1_BITBUCKET_ENDPOINT")
if !reflect.DeepEqual(testCase.expectedEndpointEnv, *env) {
t.Errorf("Expected Env and Env returned from API server differ (-want, +got): %v", cmp.Diff(testCase.expectedEndpointEnv, env))
}
assert.NotNil(t, env)
assert.Equal(t, testCase.expectedEndpointEnv, *env)
volume := util.FindVolume(deployment.Spec.Template.Spec.Volumes, "github-oauth-config")
if !reflect.DeepEqual(testCase.expectedVolume, volume) {
t.Errorf("Expected Volume and Volume returned from API server differ (-want, +got): %v", cmp.Diff(testCase.expectedVolume, volume))
}
assert.NotNil(t, volume)
assert.Equal(t, testCase.expectedVolume, volume)
volumeMount := util.FindVolumeMount(container.VolumeMounts, "github-oauth-config")
if !reflect.DeepEqual(testCase.expectedVolumeMount, volumeMount) {
t.Errorf("Expected VolumeMount and VolumeMount returned from API server differ (-want, +got): %v", cmp.Diff(testCase.expectedVolumeMount, volumeMount))
}
assert.NotNil(t, volumeMount)
assert.Equal(t, testCase.expectedVolumeMount, volumeMount)
})
}
}
func TestMountGitHubOAuthEnvVar(t *testing.T) {
type testCase struct {
name string
initObjects []runtime.Object
expectedIdKeyPathEnv corev1.EnvVar
expectedSecretKeyPathEnv corev1.EnvVar
expectedEndpointEnv corev1.EnvVar
expectedVolume corev1.Volume
expectedVolumeMount corev1.VolumeMount
}
testCases := []testCase{
{
name: "Test",
initObjects: []runtime.Object{
&corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "github-oauth-config",
Namespace: "eclipse-che",
Labels: map[string]string{
"app.kubernetes.io/part-of": "che.eclipse.org",
"app.kubernetes.io/component": "oauth-scm-configuration",
},
Annotations: map[string]string{
"che.eclipse.org/oauth-scm-server": "github",
"che.eclipse.org/scm-server-endpoint": "endpoint",
},
},
Data: map[string][]byte{
"id": []byte("some_id"),
"secret": []byte("some_secret"),
},
},
},
expectedIdKeyPathEnv: corev1.EnvVar{
Name: "CHE_OAUTH2_GITHUB_CLIENTID__FILEPATH",
Value: "/che-conf/oauth/github/id",
},
expectedSecretKeyPathEnv: corev1.EnvVar{
Name: "CHE_OAUTH2_GITHUB_CLIENTSECRET__FILEPATH",
Value: "/che-conf/oauth/github/secret",
},
expectedEndpointEnv: corev1.EnvVar{
Name: "CHE_INTEGRATION_GITHUB_SERVER__ENDPOINTS",
Value: "endpoint",
},
expectedVolume: corev1.Volume{
Name: "github-oauth-config",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: "github-oauth-config",
},
},
},
expectedVolumeMount: corev1.VolumeMount{
Name: "github-oauth-config",
MountPath: "/che-conf/oauth/github",
},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
deployContext := deploy.GetTestDeployContext(nil, testCase.initObjects)
server := NewServer(deployContext)
deployment, err := server.getDeploymentSpec()
assert.Nil(t, err, "Unexpected error %v", err)
container := &deployment.Spec.Template.Spec.Containers[0]
env := util.FindEnv(container.Env, "CHE_OAUTH2_GITHUB_CLIENTID__FILEPATH")
assert.NotNil(t, env)
assert.Equal(t, testCase.expectedIdKeyPathEnv, *env)
env = util.FindEnv(container.Env, "CHE_OAUTH2_GITHUB_CLIENTSECRET__FILEPATH")
assert.NotNil(t, env)
assert.Equal(t, testCase.expectedSecretKeyPathEnv, *env)
volume := util.FindVolume(deployment.Spec.Template.Spec.Volumes, "github-oauth-config")
assert.NotNil(t, volume)
assert.Equal(t, testCase.expectedVolume, volume)
volumeMount := util.FindVolumeMount(container.VolumeMounts, "github-oauth-config")
assert.NotNil(t, volumeMount)
assert.Equal(t, testCase.expectedVolumeMount, volumeMount)
})
}
}
func TestMountGitLabOAuthEnvVar(t *testing.T) {
type testCase struct {
name string
initObjects []runtime.Object
expectedIdKeyPathEnv corev1.EnvVar
expectedSecretKeyPathEnv corev1.EnvVar
expectedEndpointEnv corev1.EnvVar
expectedVolume corev1.Volume
expectedVolumeMount corev1.VolumeMount
}
testCases := []testCase{
{
name: "Test",
initObjects: []runtime.Object{
&corev1.Secret{
TypeMeta: metav1.TypeMeta{
Kind: "Secret",
APIVersion: "v1",
},
ObjectMeta: metav1.ObjectMeta{
Name: "gitlab-oauth-config",
Namespace: "eclipse-che",
Labels: map[string]string{
"app.kubernetes.io/part-of": "che.eclipse.org",
"app.kubernetes.io/component": "oauth-scm-configuration",
},
Annotations: map[string]string{
"che.eclipse.org/oauth-scm-server": "gitlab",
"che.eclipse.org/scm-server-endpoint": "endpoint",
},
},
Data: map[string][]byte{
"id": []byte("some_id"),
"secret": []byte("some_secret"),
},
},
},
expectedIdKeyPathEnv: corev1.EnvVar{
Name: "CHE_OAUTH_GITLAB_CLIENTID__FILEPATH",
Value: "/che-conf/oauth/gitlab/id",
},
expectedSecretKeyPathEnv: corev1.EnvVar{
Name: "CHE_OAUTH_GITLAB_CLIENTSECRET__FILEPATH",
Value: "/che-conf/oauth/gitlab/secret",
},
expectedEndpointEnv: corev1.EnvVar{
Name: "CHE_INTEGRATION_GITLAB_SERVER__ENDPOINTS",
Value: "endpoint",
},
expectedVolume: corev1.Volume{
Name: "gitlab-oauth-config",
VolumeSource: corev1.VolumeSource{
Secret: &corev1.SecretVolumeSource{
SecretName: "gitlab-oauth-config",
},
},
},
expectedVolumeMount: corev1.VolumeMount{
Name: "gitlab-oauth-config",
MountPath: "/che-conf/oauth/gitlab",
},
},
}
for _, testCase := range testCases {
t.Run(testCase.name, func(t *testing.T) {
deployContext := deploy.GetTestDeployContext(nil, testCase.initObjects)
server := NewServer(deployContext)
deployment, err := server.getDeploymentSpec()
assert.Nil(t, err, "Unexpected error %v", err)
container := &deployment.Spec.Template.Spec.Containers[0]
env := util.FindEnv(container.Env, "CHE_OAUTH_GITLAB_CLIENTID__FILEPATH")
assert.NotNil(t, env)
assert.Equal(t, testCase.expectedIdKeyPathEnv, *env)
env = util.FindEnv(container.Env, "CHE_OAUTH_GITLAB_CLIENTSECRET__FILEPATH")
assert.NotNil(t, env)
assert.Equal(t, testCase.expectedSecretKeyPathEnv, *env)
env = util.FindEnv(container.Env, "CHE_INTEGRATION_GITLAB_SERVER__ENDPOINTS")
assert.NotNil(t, env)
assert.Equal(t, testCase.expectedEndpointEnv, *env)
volume := util.FindVolume(deployment.Spec.Template.Spec.Volumes, "gitlab-oauth-config")
assert.NotNil(t, volume)
assert.Equal(t, testCase.expectedVolume, volume)
volumeMount := util.FindVolumeMount(container.VolumeMounts, "gitlab-oauth-config")
assert.NotNil(t, volumeMount)
assert.Equal(t, testCase.expectedVolumeMount, volumeMount)
})
}
}