GitLabOidcIntegration.java
package com.cloudforge.core.oidc;
import com.cloudforge.core.interfaces.Ec2Context;
import com.cloudforge.core.interfaces.OidcConfiguration;
import com.cloudforge.core.interfaces.OidcIntegration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
/**
* OIDC integration for GitLab using OmniAuth OpenID Connect.
*
* <p>GitLab has built-in OIDC support through the OmniAuth framework.
* Configuration is done via gitlab.rb for Omnibus installations.</p>
*
* <p><strong>Supported OIDC Providers:</strong></p>
* <ul>
* <li>Amazon Cognito</li>
* <li>IAM Identity Center</li>
* <li>Any OIDC-compliant provider</li>
* </ul>
*
* <p><strong>Features:</strong></p>
* <ul>
* <li>Auto-create users on first login</li>
* <li>Group synchronization from OIDC claims</li>
* <li>Admin role assignment</li>
* <li>Block external OAuth sign-ins</li>
* </ul>
*
* @see <a href="https://docs.gitlab.com/ee/administration/auth/oidc.html">GitLab OIDC Documentation</a>
*/
public class GitLabOidcIntegration implements OidcIntegration {
@Override
public boolean isSupported() {
return true;
}
@Override
public String getIntegrationMethod() {
return "Built-in OmniAuth OpenID Connect (configured via gitlab.rb)";
}
@Override
public Map<String, String> getEnvironmentVariables(OidcConfiguration config) {
// GitLab Docker containers use GITLAB_OMNIBUS_CONFIG environment variable
// This is the recommended way to configure GitLab in containers
Map<String, String> envVars = new HashMap<>();
// Build the configuration as a Ruby string that will be evaluated
StringBuilder gitlabConfig = new StringBuilder();
// Configure external URL if available (required for OAuth redirects, clone URLs, webhooks)
String externalUrl = config.getApplicationUrl();
boolean usesHttps = externalUrl != null && externalUrl.startsWith("https://");
if (externalUrl != null && !externalUrl.isEmpty()) {
gitlabConfig.append(String.format("external_url '%s'; ", externalUrl));
}
// Configure reverse proxy settings when behind ALB with HTTPS
// This prevents redirect loops by telling GitLab to trust proxy headers
if (usesHttps) {
gitlabConfig.append("nginx['listen_port'] = 80; ");
gitlabConfig.append("nginx['listen_https'] = false; ");
gitlabConfig.append("nginx['proxy_set_headers'] = { 'X-Forwarded-Proto' => 'https', 'X-Forwarded-Ssl' => 'on' }; ");
}
gitlabConfig.append("gitlab_rails['omniauth_enabled'] = true; ");
gitlabConfig.append("gitlab_rails['omniauth_allow_single_sign_on'] = ['openid_connect']; ");
gitlabConfig.append("gitlab_rails['omniauth_block_auto_created_users'] = false; ");
gitlabConfig.append("gitlab_rails['omniauth_auto_link_user'] = ['openid_connect']; ");
gitlabConfig.append("gitlab_rails['omniauth_providers'] = [");
gitlabConfig.append("{");
gitlabConfig.append("name: 'openid_connect', ");
gitlabConfig.append(String.format("label: '%s', ",
"cognito".equalsIgnoreCase(config.getProviderType()) ? "AWS Cognito" : "AWS IAM Identity Center"));
gitlabConfig.append("args: {");
gitlabConfig.append("name: 'openid_connect', ");
gitlabConfig.append("scope: ['openid', 'profile', 'email'], ");
gitlabConfig.append("response_type: 'code', ");
gitlabConfig.append(String.format("issuer: '%s', ", config.getIssuerUrl()));
gitlabConfig.append("discovery: true, ");
gitlabConfig.append("client_auth_method: 'query', ");
gitlabConfig.append(String.format("uid_field: '%s', ", config.getUsernameClaim()));
gitlabConfig.append("send_scope_to_token_endpoint: true, ");
gitlabConfig.append(String.format("pkce: %s, ", config.usePkce()));
gitlabConfig.append("client_options: {");
gitlabConfig.append(String.format("identifier: '%s', ", config.getClientId()));
gitlabConfig.append("secret: ENV['GITLAB_OIDC_CLIENT_SECRET'], ");
gitlabConfig.append(String.format("redirect_uri: '%s'", config.getRedirectUrl()));
gitlabConfig.append("}");
gitlabConfig.append("}");
gitlabConfig.append("}");
gitlabConfig.append("];");
envVars.put("GITLAB_OMNIBUS_CONFIG", gitlabConfig.toString());
return envVars;
}
@Override
public String getConfigurationFile(OidcConfiguration config) {
// GitLab Docker containers use GITLAB_OMNIBUS_CONFIG environment variable
// No config file needed - return null to skip file writing
return null;
}
@Override
public String getConfigurationFilePath() {
// GitLab Docker containers use GITLAB_OMNIBUS_CONFIG environment variable
// No config file path needed
return null;
}
@Override
public List<String> getUserDataCommands(OidcConfiguration config, Ec2Context context) {
List<String> commands = new ArrayList<>();
commands.add("# Configure GitLab OIDC integration");
commands.add("# Retrieve client secret from AWS Secrets Manager");
commands.add("export GITLAB_OIDC_CLIENT_SECRET=$(aws secretsmanager get-secret-value \\");
commands.add(" --secret-id " + config.getClientSecretArn() + " \\");
commands.add(" --query SecretString --output text)");
commands.add("");
// Create gitlab.rb configuration
commands.add("# Append OIDC configuration to gitlab.rb");
commands.add("cat >> /etc/gitlab/gitlab.rb <<'EOFGITLAB'");
commands.add("");
commands.add("# GitLab OIDC Configuration");
commands.add("# Added by CloudForge");
commands.add("");
// Configure external URL if available (required for OAuth redirects, clone URLs, webhooks)
String externalUrl = config.getApplicationUrl();
if (externalUrl != null && !externalUrl.isEmpty()) {
commands.add("# Configure GitLab external URL for reverse proxy");
commands.add("external_url '" + externalUrl + "'");
commands.add("");
}
commands.add("gitlab_rails['omniauth_enabled'] = true");
commands.add("gitlab_rails['omniauth_allow_single_sign_on'] = ['openid_connect']");
commands.add("gitlab_rails['omniauth_block_auto_created_users'] = false");
commands.add("gitlab_rails['omniauth_auto_link_user'] = ['openid_connect']");
commands.add("");
commands.add("gitlab_rails['omniauth_providers'] = [");
commands.add(" {");
commands.add(" name: 'openid_connect',");
commands.add(" label: '" + ("cognito".equalsIgnoreCase(config.getProviderType()) ? "AWS Cognito" : "AWS IAM Identity Center") + "',");
commands.add(" args: {");
commands.add(" name: 'openid_connect',");
commands.add(" scope: ['openid', 'profile', 'email'],");
commands.add(" response_type: 'code',");
commands.add(" issuer: '" + config.getIssuerUrl() + "',");
commands.add(" discovery: true,");
commands.add(" client_auth_method: 'query',");
commands.add(" uid_field: '" + config.getUsernameClaim() + "',");
commands.add(" send_scope_to_token_endpoint: true,");
commands.add(" pkce: " + config.usePkce() + ",");
commands.add(" client_options: {");
commands.add(" identifier: '" + config.getClientId() + "',");
commands.add(" secret: '${GITLAB_OIDC_CLIENT_SECRET}',");
commands.add(" redirect_uri: '" + config.getRedirectUrl() + "'");
commands.add(" }");
commands.add(" }");
commands.add(" }");
commands.add("]");
commands.add("EOFGITLAB");
commands.add("");
// Replace secret placeholder with actual value
commands.add("# Replace secret placeholder with actual value");
commands.add("sed -i \"s|\\${GITLAB_OIDC_CLIENT_SECRET}|$GITLAB_OIDC_CLIENT_SECRET|g\" /etc/gitlab/gitlab.rb");
commands.add("");
// Reconfigure GitLab
commands.add("# Reconfigure GitLab to apply changes");
commands.add("gitlab-ctl reconfigure");
commands.add("echo 'GitLab OIDC integration configured' >> /var/log/userdata.log");
return commands;
}
@Override
public String getContainerStartupCommand() {
// GitLab's official omnibus container uses /assets/init-container as the default CMD
// Per https://github.com/gitlabhq/omnibus-gitlab/blob/master/docker/Dockerfile
// The init-container script handles initialization, signals, runit, and GitLab reconfiguration
return "/assets/init-container";
}
@Override
public boolean supportsCognito() {
// Full support - GitLab OmniAuth works with Cognito OIDC
return true;
}
@Override
public boolean supportsIdentityCenterSaml() {
// GitLab supports SAML (Premium/Ultimate) but this integration uses OIDC
// For SAML, create a GitLabSamlIntegration class
return false;
}
@Override
public String getAuthenticationType() {
return "OIDC";
}
@Override
public String getPostDeploymentInstructions() {
return """
GitLab OIDC Integration Completed
==================================
1. Access GitLab at: https://{your-domain}
2. Click "Sign in with %s" on the login page
3. You will be redirected to the OIDC provider
4. After authentication, a GitLab account will be created automatically
User Management:
- Users are auto-created on first OIDC login
- User accounts are linked to OIDC identity
- To grant admin privileges, use GitLab Rails console:
gitlab-rails console
user = User.find_by(email: 'user@example.com')
user.admin = true
user.save!
Group Synchronization:
- Consider GitLab Group Sync for automatic role mapping
- Requires GitLab Premium/Ultimate for SAML Group Links
""";
}
}