cloudogu / sonar-cas-plugin

CAS Authentication support for SonarQube
14 stars 8 forks source link

Sonarqube parse CAS-ticket error: User name must not be blank #29

Closed peter-sun-ryu closed 1 year ago

peter-sun-ryu commented 3 years ago

@ppxl Error Description OS version: Win10 Tomcat version: 8.5 SonarQube version: 7.9.5 LTS CAS plugin version: 2.0.0 CAS Server version: 5.3.16 CAS Server url: http://cas.example.org:8087/cas/login CAS application.properties(partial configured)

cas.authn.accept.users=test::test
cas.tgc.secure=false
cas.serviceRegistry.initFromJson=true

SonarQube url: http://localhost:9000/sq sonar.properties(total configured)

sonar.web.context=/sq
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.web.sso.refreshIntervalInMinutes=5
sonar.security.realm=cas
sonar.authenticator.createUsers=true
sonar.cas.forceCasLogin=true
sonar.cas.protocol=cas3
sonar.cas.casServerUrlPrefix=http://cas.example.org:8087/cas
sonar.cas.casServerLoginUrl=http://cas.example.org:8087/cas/login
sonar.cas.sonarServerUrl=http://localhost:9000/sq
sonar.cas.casServerLogoutUrl=http://cas.example.org:8087/cas/logout
sonar.cas.sendGateway=false
sonar.cas.sessionStorePath=D:/DevOps/sonarqube-7.9.5/data/sonarcas/sessionstore
sonar.cas.sessionStore.cleanUpIntervalInSeconds=1800
sonar.cas.saml11.toleranceMilliseconds=1000
sonar.cas.disableCertValidation=true
sonar.cas.urlAfterCasRedirectCookieMaxAgeSeconds=300

Description: After intalling CAS plugin on SonarQube, start SonarQube by http://localhost:9000/sq, SonarQube can redirect to CAS server http://cas.example.org:8087/cas/login. Use the test/test can login success and CAS generate ticket to SonarQube by url:http://localhost:9000/sq/sessions/init/cas?ticket=ST-1-e3Y6-hJgjUw-0yBbKtgWNmvYl-gDESKTOP-C9UVVKK But the web page is empty. Then there is some error in logs/web.log as below. Error Message

2021.01.21 22:33:20 ERROR web[AXclXR2FmEN5uUKAAAAC][o.s.p.c.CasIdentityProvider] authentication or logout failed
java.lang.IllegalArgumentException: User name must not be blank
        at org.sonar.api.internal.google.common.base.Preconditions.checkArgument(Preconditions.java:122)
        at org.sonar.api.server.authentication.UserIdentity$Builder.validateName(UserIdentity.java:233)
        at org.sonar.api.server.authentication.UserIdentity$Builder.build(UserIdentity.java:214)
        at org.sonar.plugins.cas.LoginHandler.createUserIdentity(LoginHandler.java:103)
        at org.sonar.plugins.cas.LoginHandler.handleLogin(LoginHandler.java:64)
        at org.sonar.plugins.cas.CasIdentityProvider.init(CasIdentityProvider.java:69)
        at org.sonar.server.authentication.InitFilter.handleBaseIdentityProvider(InitFilter.java:106)
        at org.sonar.server.authentication.InitFilter.handleProvider(InitFilter.java:80)
        at org.sonar.server.authentication.InitFilter.doFilter(InitFilter.java:73)
        at org.sonar.server.platform.web.MasterServletFilter$GodFilterChain.doFilter(MasterServletFilter.java:126)
        at org.sonar.server.platform.web.MasterServletFilter.doFilter(MasterServletFilter.java:95)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.sonar.server.user.UserSessionFilter.doFilter(UserSessionFilter.java:87)
        at org.sonar.server.user.UserSessionFilter.doFilter(UserSessionFilter.java:71)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.sonar.server.platform.web.CacheControlFilter.doFilter(CacheControlFilter.java:76)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.sonar.server.platform.web.SecurityServletFilter.doHttpFilter(SecurityServletFilter.java:76)
        at org.sonar.server.platform.web.SecurityServletFilter.doFilter(SecurityServletFilter.java:48)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.sonar.server.platform.web.RedirectFilter.doFilter(RedirectFilter.java:58)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.sonar.server.platform.web.requestid.RequestIdFilter.doFilter(RequestIdFilter.java:63)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.sonar.server.platform.web.RootFilter.doFilter(RootFilter.java:62)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.catalina.filters.SetCharacterEncodingFilter.doFilter(SetCharacterEncodingFilter.java:109)
        at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:193)
        at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:166)
        at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:199)
        at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:96)
        at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:493)
        at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140)
        at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:81)
        at ch.qos.logback.access.tomcat.LogbackValve.invoke(LogbackValve.java:256)
        at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87)
        at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:342)
        at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:800)
        at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66)
        at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:806)
        at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.doRun(NioEndpoint.java:1498)
        at org.apache.tomcat.util.net.SocketProcessorBase.run(SocketProcessorBase.java:49)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
        at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61)
        at java.base/java.lang.Thread.run(Thread.java:834)
ppxl commented 3 years ago

Hi, and thanks for your question.

I see you use CAS Server v5.3.16. I am not unsure if the configuration did change to the CAS version I have tested the plugin with. I need to check if I can reproduce the problem and would then come back to you.

peter-sun-ryu commented 3 years ago

Hi, and thanks for your question.

I see you use CAS Server v5.3.16. I am not unsure if the configuration did change to the CAS version I have tested the plugin with. I need to check if I can reproduce the problem and would then come back to you.

Dear ppxl Hi~ Have you check the error? Wait for your reply. Thanks

ppxl commented 3 years ago

Hi, thank you for your patience. Please have my apologies for the limited feedback right now because I had some problems in reproducing the set-up with more recent versions of CAS.

Anyhow our CAS connoisseur :wink:, @mbehlendorf, pinged me with an idea which I'd like to forward to you:

Would you kindly check that:

  1. the CAS property for displayName is properly set?
  2. the Sonar-CAS plugin property displayName matches with the CAS configuration?

For the background:

CAS is supposed to provide user and group attributes during the login procedure. Our Sonar-CAS plugin needs to know about certain user and group attributes in order to orderly establish both CAS authentication as well as to replicate user information towards SonarQube.

For CAS, the appropriate property depends on the CAS version as well as the used user/group data storage solution. But it may look like this:

...
cas.authn.attributeRepository.ldap[0].attributes.displayName=displayName
cas.authn.attributeRepository.ldap[0].attributes.givenName=givenName
cas.authn.attributeRepository.ldap[0].attributes.mail=email
...

Likewise, the Sonar-CAS plugin needs to know for which attribute it should look at. This property is supposed to be configured within the sonar.properties file, like so:

....
sonar.cas.fullNameAttribute=displayName
....

You can find more about configuring the Sonar-CAS plugin in the documentation.

peter-sun-ryu commented 3 years ago

Dear @ppxl According to your solution,I try to change the configuration of SonarQube and CAS server. Now the properties configuration file as below. Sonarqube(sonar.properties)

sonar.web.context=/sq

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.web.sso.refreshIntervalInMinutes=5

sonar.security.realm=cas
sonar.authenticator.createUsers=true
sonar.cas.forceCasLogin=true
sonar.cas.protocol=cas3
sonar.cas.casServerUrlPrefix=http://cas.example.org:8087/cas
sonar.cas.casServerLoginUrl=http://cas.example.org:8087/cas/login
sonar.cas.sonarServerUrl=http://localhost:9000/sq
sonar.cas.casServerLogoutUrl=http://cas.example.org:8087/cas/logout
sonar.cas.sendGateway=false
sonar.cas.sessionStorePath=D:/DevOps/sonarqube-7.9.5/data/sonarcas/sessionstore
sonar.cas.sessionStore.cleanUpIntervalInSeconds=1800

# NEW ADDED
sonar.cas.rolesAttributes=groups,roles
sonar.cas.fullNameAttribute=displayName
sonar.cas.eMailAttribute=mail

sonar.cas.saml11.toleranceMilliseconds=1000
sonar.cas.disableCertValidation=true
sonar.cas.urlAfterCasRedirectCookieMaxAgeSeconds=300

CAS(application.properties)

##
# CAS Server Context Configuration
#
server.context-path=/cas
server.port=8443

server.ssl.key-store=file:/etc/cas/thekeystore
server.ssl.key-store-password=changeit
server.ssl.key-password=changeit

server.max-http-header-size=2097152
server.use-forward-headers=true
server.connection-timeout=20000
server.error.include-stacktrace=ALWAYS

server.compression.enabled=true
server.compression.mime-types=application/javascript,application/json,application/xml,text/html,text/xml,text/plain

server.tomcat.max-http-post-size=2097152
server.tomcat.basedir=build/tomcat
server.tomcat.accesslog.enabled=true
server.tomcat.accesslog.pattern=%t %a "%r" %s (%D ms)
server.tomcat.accesslog.suffix=.log
server.tomcat.min-spare-threads=10
server.tomcat.max-threads=200
server.tomcat.port-header=X-Forwarded-Port
server.tomcat.protocol-header=X-Forwarded-Proto
server.tomcat.protocol-header-https-value=https
server.tomcat.remote-ip-header=X-FORWARDED-FOR
server.tomcat.uri-encoding=UTF-8

spring.http.encoding.charset=UTF-8
spring.http.encoding.enabled=true
spring.http.encoding.force=true

##
# CAS Cloud Bus Configuration
#
spring.cloud.bus.enabled=false

# Indicates that systemPropertiesOverride can be used.
# Set to false to prevent users from changing the default accidentally. Default true.
spring.cloud.config.allow-override=true

# External properties should override system properties.
spring.cloud.config.override-system-properties=false

# When allowOverride is true, external properties should take lowest priority, and not override any
# existing property sources (including local config files).
spring.cloud.config.override-none=false

# spring.cloud.bus.refresh.enabled=true
# spring.cloud.bus.env.enabled=true
# spring.cloud.bus.destination=CasCloudBus
# spring.cloud.bus.ack.enabled=true

endpoints.enabled=false
endpoints.sensitive=true

endpoints.restart.enabled=false
endpoints.shutdown.enabled=false

# Control the security of the management/actuator endpoints
# The 'enabled' flag below here controls the rendering of details for the health endpoint amongst other things.
management.security.enabled=true
management.security.roles=ACTUATOR,ADMIN
management.security.sessions=if_required
management.context-path=/status
management.add-application-context-header=false

# Define a CAS-specific "WARN" status code and its order
management.health.status.order=WARN, DOWN, OUT_OF_SERVICE, UNKNOWN, UP

# Control the security of the management/actuator endpoints
# With basic authentication, assuming Spring Security and/or relevant modules are on the classpath.
security.basic.authorize-mode=role
security.basic.path=/cas/status/**
# security.basic.enabled=true
# security.user.name=casuser
# security.user.password=

##
# CAS Web Application Session Configuration
#
server.session.timeout=300
server.session.cookie.http-only=true
server.session.tracking-modes=COOKIE

##
# CAS Thymeleaf View Configuration
#
spring.thymeleaf.encoding=UTF-8
spring.thymeleaf.cache=true
spring.thymeleaf.mode=HTML
spring.thymeleaf.template-resolver-order=100
##
# CAS Log4j Configuration
#
# logging.config=file:/etc/cas/log4j2.xml
server.context-parameters.isLog4jAutoInitializationDisabled=true

##
# CAS AspectJ Configuration
#
spring.aop.auto=true
spring.aop.proxy-target-class=true

##
# CAS Authentication Credentials
#
cas.authn.accept.users=test::abc
# cas.authn.attributeRepository.ldap[0].attributes.displayName=displayName
# cas.authn.attributeRepository.ldap[0].attributes.givenName=givenName
# cas.authn.attributeRepository.ldap[0].attributes.mail=mail
cas.authn.attributeRepository.stub.attributes.displayName=displayName
cas.authn.attributeRepository.stub.attributes.givenName=givenName
cas.authn.attributeRepository.stub.attributes.mail=mail

# http auth
cas.tgc.secure=false
cas.serviceRegistry.initFromJson=true

Result(sonar/logs/web.log) : User name must not be blank

...
2021.02.03 17:05:20 ERROR web[AXdnF9QvF5pRev1+AAAQ][o.s.p.c.CasIdentityProvider] authentication or logout failed
java.lang.IllegalArgumentException: User name must not be blank
        at org.sonar.api.internal.google.common.base.Preconditions.checkArgument(Preconditions.java:122)
        at org.sonar.api.server.authentication.UserIdentity$Builder.validateName(UserIdentity.java:233)
...

PS: I used 'cas.authn.attributeRepository.ldap[0].attributes.displayName=displayName' configuration, but it didn't work either.

bcuestav commented 2 years ago

Same problem using Apereo CAS 6.2.6 and sonar-cas-plugin 4.2.0 in Sonarqube 9.1. I try all configurations described in this post, but always get "java.lang.IllegalArgumentException: User name must not be blank".

Sonarqube is a clean installation in dev environment and admin password not stablished yet. Could be it the problem?

bcuestav commented 2 years ago

Hi, I just resolve it. Simply use fullNameAttribute=username. This is my configuration:

  sonar.security.realm: cas
  sonar.authenticator.createUsers: 'true'
  sonar.cas.forceCasLogin: 'true'
  sonar.cas.protocol: cas3
  sonar.cas.casServerUrlPrefix: https://xxx/cas-1
  sonar.cas.casServerLoginUrl: https://xxx/cas-1/login
  sonar.cas.casServerLogoutUrl: https://xxx/cas-1/logout
  sonar.cas.sonarServerUrl: http://xxx:9000
  sonar.cas.rolesAttributes: groups,roles
  sonar.cas.sessionStorePath: /tmp/sonarcas/sessionstore
  sonar.cas.sessionStore.cleanUpIntervalInSeconds: 1800
  sonar.cas.fullNameAttribute: username
  sonar.cas.eMailAttribute: email
  sonar.cas.urlAfterCasRedirectCookieMaxAgeSeconds: 300
  SONARQUBE_WEB_JVM_OPTS: -agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5000
ppxl commented 2 years ago

Hey @bcuestav, thank you for your contribution! I think I will document your solution for the community. :+1:

UnkownnHacker commented 2 years ago

Hi @ppxl Is there a solution to this problem? I'm having the same problem with version 8.9.6 of sonarqube when using version 4.2.0 of plugin, I tried the above method but it didn't solve the problem. I always get "java.lang.IllegalArgumentException: User name must not be blank" error. Thanks!

py-mu commented 1 year ago

Does the attribute output by the cas server contain displayName

visit your cas url and login, you will get info like:

微信图片_20220927143015

I think you need to set some return fields in the service registration on the CAS server.

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "^(https|imaps|http)://.*",
  "name" : "srap",
  "id" : 1000,
  "description": "srap安全测试",
  "evaluationOrder" : 10,
  "attributeReleasePolicy" : {
    "@class" : "org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy"
    "allowedAttributes" : [ "java.util.ArrayList", [ "name", "username", "email" ] ]
  }
}

at sonar.properties file:

# if cas server return displayName
# sonar.cas.fullNameAttribute=displayName
sonar.cas.fullNameAttribute=username

the end, I hope I'm not late.

微信截图_20220927145009

ppxl commented 1 year ago

Does the attribute output by the cas server contain displayName

visit your cas url and login, you will get info like:

微信图片_20220927143015

I think you need to set some return fields in the service registration on the CAS server.

{
  "@class" : "org.apereo.cas.services.RegexRegisteredService",
  "serviceId" : "^(https|imaps|http)://.*",
  "name" : "srap",
  "id" : 1000,
  "description": "srap安全测试",
  "evaluationOrder" : 10,
  "attributeReleasePolicy" : {
    "@class" : "org.apereo.cas.services.ReturnAllowedAttributeReleasePolicy"
    "allowedAttributes" : [ "java.util.ArrayList", [ "name", "username", "email" ] ]
  }
}

at sonar.properties file:

# if cas server return displayName
# sonar.cas.fullNameAttribute=displayName
sonar.cas.fullNameAttribute=username

the end, I hope I'm not late.

微信截图_20220927145009

Thank you for adding more information :+1: I am closing this ticket then.