Must-share information (formatted with Markdown):
- Which versions are you using (SonarQube Server / Community Build, Scanner, Plugin, and any relevant extension)
SonarQube Server / Community Build:sonarqube:25.7.0.110598-community
- How is SonarQube deployed: zip, Docker, Helm
Docker - What are you trying to achieve
SAML authentication with Microsoft Entra ID - What have you tried so far to achieve this
Configured SAML authentication following official documentation
I want to share how I successfully implemented SAML authentication with Microsoft Entra ID, as I encountered the following error:
/sessions/unauthorized
You're not authorized to access this page. Please contact the administrator.
Although the “Test Configuration” for SAML worked successfully:
/saml/validation
SAML Authentication Test
Success
In debug mode, the web.log
showed the following error:
DEBUG web[8adccbd1-ea78-4a6c-a0b1-dd00e84a322d][auth.event] login failure [cause|Cookie 'OAUTHSTATE' is missing][method|OAUTH2][provider|EXTERNAL|SAML][IP|172.18.0.4|172.18.0.1][login|]
I followed these tutorials:
- Registering SonarQube Server in Microsoft Entra ID | Documentation
- Configure SonarQube for Single Sign-On with Microsoft Entra ID - Microsoft Entra ID | Microsoft Learn
I researched these errors in the SonarQube community and online but found no successful solutions. The issue appeared related to how Chromium-based browsers (e.g., Edge) handle cookies, as the error occurred in Edge but not in Firefox.
I deployed SonarQube using Docker, but to resolve the issue, I needed to deploy it behind Nginx with HTTPS. In my lab, I used a localhost
URL with a certificate generated using mkcert
. Below are the configurations:
Certificate Generation
# Install mkcert with winget
winget install FiloSottile.mkcert
# Create local CA
mkcert -install
# Generate certificate for localhost
mkcert localhost 127.0.0.1 ::1
# Move generated files
move localhost+2.pem ./Web/sonarqube.crt
move localhost+2-key.pem ./Web/sonarqube.key
docker-compose.yml
services:
sonarqube:
image: sonarqube:community
container_name: sonarqube
restart: unless-stopped
depends_on:
- sonarqube_db
env_file:
- ./WEB/.env-sonarqube
networks:
- sonarqube-network
ports:
- '9000:9000'
volumes:
- sonarqube_conf:/opt/sonarqube/conf
- sonarqube_data:/opt/sonarqube/data
- sonarqube_extensions:/opt/sonarqube/extensions
- sonarqube_logs:/opt/sonarqube/logs
- sonarqube_temp:/opt/sonarqube/temp
- ./Plugins:/opt/sonarqube/extensions/plugins
sonarqube_db:
image: mcr.microsoft.com/mssql/server:2022-latest
container_name: sonarqube_db-sqlserver
restart: unless-stopped
networks:
- sonarqube-network
environment:
- MSSQL_DATA_DIR=/var/opt/mssql/data
- MSSQL_LOG_DIR=/var/opt/mssql/log
- MSSQL_BACKUP_DIR=/var/opt/mssql/backup
env_file:
- ./MSSQLSERVER/.env-sqlserver
- ./MSSQLSERVER/.env-sapassword
ports:
- '1433:1433'
volumes:
- sql-server-data:/var/opt/mssql/
- ./MSSQLSERVER:/var/opt/mssql/backup
- ./MSSQLSERVER/setup.sql:/docker-entrypoint-initdb.d/init.sql
nginx:
image: nginx:latest
container_name: sonar-nginx
restart: unless-stopped
ports:
- "80:80"
- "443:443"
volumes:
- ./WEB/nginx.conf:/etc/nginx/nginx.conf:ro
- ./WEB/sonarqube.crt:/etc/nginx/ssl/sonarqube.crt:ro
- ./WEB/sonarqube.key:/etc/nginx/ssl/sonarqube.key:ro
depends_on:
- sonarqube
networks:
- sonarqube-network
networks:
sonarqube-network:
driver: bridge
volumes:
sonarqube_conf:
sonarqube_temp:
sonarqube_data:
sonarqube_logs:
sonarqube_extensions:
sql-server-data:
driver: local
.\WEB.env-sonarqube
SONAR_WEB_JAVAOPTS=-Xmx2g -Xms2g -Dserver.use-forward-headers=true -Dserver.forward-headers-strategy=framework -Dserver.tomcat.redirect-context-root=false -Dserver.tomcat.use-relative-redirects=false -Dserver.servlet.session.cookie.same-site=None -Dserver.servlet.session.cookie.secure=true -XX:+HeapDumpOnOutOfMemoryError
SONAR_WEB_JAVAADDITIONALOPTS=-Dserver.use-forward-headers=true -Dserver.forward-headers-strategy=framework -Dspring.session.cookie.same-site=None -javaagent:./extensions/plugins/sonarqube-community-branch-plugin-25.6.0.jar=web
SONAR_CE_JAVAOPTS=-Xmx1G -Xms1G -XX:+HeapDumpOnOutOfMemoryError
SONAR_CE_JAVAADDITIONALOPTS=-javaagent:./extensions/plugins/sonarqube-community-branch-plugin-25.6.0.jar=ce
SONAR_WEB_SSO_ENABLE=true
SONAR_WEB_SSO_LOGINHEADER=X-Forwarded-Login
SONAR_WEB_SSO_NAMEHEADER=X-Forwarded-Name
SONAR_WEB_SSO_EMAILHEADER=X-Forwarded-Email
SONAR_WEB_SSO_GROUPSHEADER=X-Forwarded-Groups
SONAR_JDBC_URL=jdbc:sqlserver://sonarqube_db-sqlserver;databaseName=sonarqube_original;encrypt=true;trustServerCertificate=true
SONAR_JDBC_USERNAME=sonarqube
SONAR_JDBC_PASSWORD=sonarqube
.\WEB\nginx.conf
events {
worker_connections 1024;
}
http {
# Basic configuration
include /etc/nginx/mime.types;
default_type application/octet-stream;
# Logs
access_log /var/log/nginx/access.log;
error_log /var/log/nginx/error.log;
# HTTP server - Redirect to HTTPS
server {
listen 80;
server_name localhost;
return 301 https://$server_name$request_uri;
}
# HTTPS server - SonarQube
server {
listen 443 ssl;
http2 on;
server_name localhost;
# SSL configuration
ssl_certificate /etc/nginx/ssl/sonarqube.crt;
ssl_certificate_key /etc/nginx/ssl/sonarqube.key;
# Enhanced SSL settings
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers ECDHE-RSA-AES128-GCM-SHA256:ECDHE-RSA-AES256-GCM-SHA384:ECDHE-RSA-AES128-SHA256:ECDHE-RSA-AES256-SHA384;
ssl_prefer_server_ciphers off;
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
# Security headers (adjusted for cross-site cookies)
add_header X-Frame-Options SAMEORIGIN;
add_header X-Content-Type-Options nosniff;
add_header X-XSS-Protection "1; mode=block";
# Proxy configuration for SonarQube
location / {
proxy_pass http://sonarqube:9000;
# Critical headers for HTTPS
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto https;
proxy_set_header X-Forwarded-Ssl on;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Forwarded-Port 443;
proxy_set_header X-Scheme https;
proxy_set_header X-Forwarded-Protocol https;
proxy_set_header X-Forwarded-Prefix "";
proxy_set_header X-Url-Scheme https;
# Headers for SAML cookies - Critical for Edge
proxy_set_header Cookie $http_cookie;
proxy_pass_header Set-Cookie;
# Cross-site cookie settings (Edge compatibility)
proxy_cookie_path / /;
proxy_cookie_domain localhost localhost;
proxy_cookie_flags ~ secure;
# Additional proxy settings
proxy_connect_timeout 60s;
proxy_send_timeout 60s;
proxy_read_timeout 60s;
proxy_buffering off;
proxy_request_buffering off;
proxy_redirect off;
# Buffer size for SAML
proxy_buffer_size 32k;
proxy_buffers 8 32k;
proxy_busy_buffers_size 64k;
}
location /sessions/init/saml {
proxy_pass http://sonarqube:9000/sessions/init/saml;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header Cookie $http_cookie;
proxy_pass_header Set-Cookie;
proxy_cookie_path / /;
proxy_cookie_domain localhost localhost;
# Add SameSite=None to OAUTHSTATE cookie
proxy_cookie_flags OAUTHSTATE samesite=none secure;
}
location /oauth2/callback/saml {
proxy_pass http://sonarqube:9000/oauth2/callback/saml;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header X-Forwarded-Port $server_port;
proxy_set_header Cookie $http_cookie;
proxy_pass_header Set-Cookie;
proxy_cookie_path / /;
proxy_cookie_domain localhost localhost;
# Add SameSite=None to any cookie in the callback
proxy_cookie_flags ~ samesite=none secure;
}
}
}
Microsoft Entra ID Enterprise Application Configuration
Basic SAML Configuration
Identifier (Entity ID): sonarqube
Reply URL (Assertion Consumer Service URL): https://localhost/oauth2/callback/saml
Sign on URL: https://localhost
Relay State (Optional): Optional
Logout Url (Optional): https://localhost/sessions/logout
SonarQube UI Configuration
Administration > Configuration > General Settings > Authentication > SAML > SAML Configuration:
* SAML user login attribute*: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name
* SAML user name attribute*: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/givenname
* SAML user email attribute: http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress
* SAML group attribute: http://schemas.microsoft.com/ws/2008/06/identity/claims/groups
Administration > Configuration > General Settings > General:
* Server base URL: https://localhost
I hope this guide helps others facing similar issues or serves as a reference for myself in the future.