jenkinsci / cas-plugin

Jenkins CAS Plugin
https://plugins.jenkins.io/cas-plugin/
MIT License
9 stars 16 forks source link

CAS 3.0 XML authentication does not work with empty groups/roles attribute #7

Closed db0 closed 3 years ago

db0 commented 3 years ago

Because my JSON authentication was broken due to #6, I tried to fallback to XML. Unfortunately this seems it doesn't work at all. I authenticate on CAS, but when returning to Jenkins, it says something didn't work.

In the log, I see the XML was returned correctly, so it looks like it's failing to parse something.

However the CAS 2.0 XML works.

I'm pastingthe sample returning XMLs from the two versions

CAS 3.0 XML (Doesn't work)

Server response: <?xml version="1.0" encoding="utf-8"?>
<cas:serviceResponse xmlns:cas="http://www.yale.edu/tp/cas">
    <cas:authenticationSuccess>
        <cas:user>username</cas:user>
        <cas:attributes>
            <cas:authenticationDate>2021-02-01T09:42:43.344+01:00</cas:authenticationDate>
            <cas:longTermAuthenticationRequestTokenUsed>false</cas:longTermAuthenticationRequestTokenUsed>
            <cas:isFromNewLogin>false</cas:isFromNewLogin>
            <cas:departmentNumber>DEPT</cas:departmentNumber>
            <cas:email>firstname.lastname@example.com</cas:email>
            <cas:employeeNumber>0000000</cas:employeeNumber>
            <cas:employeeType>x</cas:employeeType>
            <cas:firstName>Name</cas:firstName>
            <cas:lastName>SURNAME</cas:lastName>
            <cas:domain>example.com</cas:domain>
            <cas:domainUsername>username</cas:domainUsername>
            <cas:telephoneNumber>00000</cas:telephoneNumber>
            <cas:locale>en</cas:locale>
            <cas:assuranceLevel>00</cas:assuranceLevel>
            <cas:uid>username</cas:uid>
            <cas:orgId>000000</cas:orgId>
            <cas:teleworkingPriority>false</cas:teleworkingPriority>
            <cas:groups number="0"/>
            <cas:authenticationLevel>BASIC</cas:authenticationLevel>
            <cas:strengths number="1">
                <cas:strength>STRONG</cas:strength>
            </cas:strengths>
            <cas:authenticationFactors number="1">
                <cas:moniker>firstname.lastname@example.com</cas:moniker>
            </cas:authenticationFactors>
            <cas:ticketType>SERVICE</cas:ticketType>
        </cas:attributes>
    </cas:authenticationSuccess>
</cas:serviceResponse>

CAS 2.0 XML (works)

<cas:serviceResponse xmlns:cas="https://example.com/cas/schemas"
                     server="CAS NAME version 1.1.1.b.11111 - 25/01/2021 - 16:41"
                     date="2021-02-01T10:03:49.893+01:00"
                     version="1.1">
    <cas:authenticationSuccess>
        <cas:user>username</cas:user>
        <cas:groups number="1">
            <cas:group>INTERNET</cas:group>
        </cas:groups>
        <cas:authenticationLevel>BASIC</cas:authenticationLevel>
        <cas:strengths number="1">
            <cas:strength>STRONG</cas:strength>
        </cas:strengths>
        <cas:authenticationFactors number="1">
            <cas:moniker>firstname.lastname@example.com</cas:moniker>
        </cas:authenticationFactors>
        <cas:loginDate>2021-02-01T09:42:43.344+01:00</cas:loginDate>
        <cas:sso>true</cas:sso>
        <cas:ticketType>SERVICE</cas:ticketType>
    </cas:authenticationSuccess>
</cas:serviceResponse>
fcrespel commented 3 years ago

Is there any error message available in the logs? Maybe something like A granted authority textual representation is required?

By looking at the responses, the only notable difference I see is <cas:groups number="0"/> in the CAS 3.0 one, which translates to an empty attribute. In the default plugin configuration the "groups" attribute is used to determine roles, but Spring Security doesn't allow empty role names.

If you don't have any error in the logs, try changing the Advanced options of the CAS 3.0 protocol in the plugin config, remove "groups" from the "Roles Attribute(s)" and try again. If it doesn't help, try adding a custom logger in the Jenkins settings, with the org.jasig.cas and org.jenkinsci.plugins.cas packages at the finest log level.

db0 commented 3 years ago

I have enabled more logs as instructed (I was already grabbing the XML from org.jasig.cas.client) but unfortunately there's nothing shown. The log immediately ends after the XML is shown :-/

Feb 02, 2021 1:37:31 PM FINE org.jasig.cas.client.validation.AbstractUrlBasedTicketValidator validate

Retrieving response from server.

Feb 02, 2021 1:37:31 PM FINE org.jasig.cas.client.validation.AbstractUrlBasedTicketValidator validate
Server response: <?xml version="1.0" encoding="utf-8"?>
...
</cas:serviceResponse>

However it does looks like it's related to the groups. When groups are returned empty in CAS 3.0, Jenkins throws an error. When at least 1 group is returned, it works fine.

Surpisingly, using CAS 2.0 works with empty groups however.

fcrespel commented 3 years ago

Could you please try again with loggers for org.springframework.security and hudson.security ?

db0 commented 3 years ago

This is what follows from those loggers after the XML

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/securityRealm/finishLogin @3 org.springframework.security.cas.web.CasAuthenticationFilter@1e8f0ffd « java.lang.IllegalArgumentException: A granted authority textual representation is required: 200

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/securityRealm/finishLogin @3 org.jenkinsci.plugins.cas.spring.security.CasSingleSignOutFilter@b129dd3 « java.lang.IllegalArgumentException: A granted authority textual representation is required: 200

Feb 02, 2021 5:33:55 PM FINE org.springframework.security.web.context.HttpSessionSecurityContextRepository$SaveToSessionResponseWrapper saveContext

Did not store empty SecurityContext

Feb 02, 2021 5:33:55 PM FINE org.springframework.security.web.context.SecurityContextPersistenceFilter doFilter

Cleared SecurityContextHolder to complete request

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/securityRealm/finishLogin @3 hudson.security.HttpSessionContextIntegrationFilter2@786a250e « java.lang.IllegalArgumentException: A granted authority textual representation is required: 200

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/securityRealm/finishLogin @1 hudson.security.ChainedServletFilter@4123347 « java.lang.IllegalArgumentException: A granted authority textual representation is required: 200

Feb 02, 2021 5:33:55 PM FINER hudson.security.HudsonFilter doFilter

ENTRY

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

starting filter on /

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @1 hudson.security.ChainedServletFilter@4123347 »

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

starting filter on /

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @1 hudson.security.HttpSessionContextIntegrationFilter2@786a250e »

Feb 02, 2021 5:33:55 PM FINEST org.springframework.security.web.context.HttpSessionSecurityContextRepository readSecurityContextFromSession

No HttpSession currently exists

Feb 02, 2021 5:33:55 PM FINEST org.springframework.security.web.context.HttpSessionSecurityContextRepository loadContext

Created SecurityContextImpl [Null authentication]

Feb 02, 2021 5:33:55 PM FINE org.springframework.security.web.context.SecurityContextPersistenceFilter doFilter

Set SecurityContextHolder to empty SecurityContext

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @2 org.jenkinsci.plugins.cas.spring.security.CasSingleSignOutFilter@b129dd3 »

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @3 org.springframework.security.cas.web.CasAuthenticationFilter@1e8f0ffd »

Feb 02, 2021 5:33:55 PM FINEST org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter requiresAuthentication

Did not match request to Ant [pattern='/securityRealm/finishLogin']

Feb 02, 2021 5:33:55 PM FINE org.springframework.security.cas.web.CasAuthenticationFilter serviceTicketRequest

serviceTicketRequest = false

Feb 02, 2021 5:33:55 PM FINE org.springframework.security.cas.web.CasAuthenticationFilter proxyReceptorConfigured

proxyReceptorConfigured = false

Feb 02, 2021 5:33:55 PM FINE org.springframework.security.cas.web.CasAuthenticationFilter proxyReceptorRequest

proxyReceptorRequest = false

Feb 02, 2021 5:33:55 PM FINE org.springframework.security.cas.web.CasAuthenticationFilter proxyTicketRequest

proxyTicketRequest = false

Feb 02, 2021 5:33:55 PM FINE org.springframework.security.cas.web.CasAuthenticationFilter requiresAuthentication

requiresAuthentication = false

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ end: 200

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @2 hudson.security.ChainedServletFilter@5fbba »

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

starting filter on /

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @1 hudson.security.HttpSessionContextIntegrationFilter2@3178efbd »

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @2 jenkins.security.BasicHeaderProcessor@1813eec9 »

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @3 hudson.security.AuthenticationProcessingFilter2@7f0041d »

Feb 02, 2021 5:33:55 PM FINEST org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter requiresAuthentication

Did not match request to Ant [pattern='/j_spring_security_check', POST]

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @4 org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter@61e603f9 »

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @5 org.springframework.security.web.authentication.AnonymousAuthenticationFilter@17950d7f »

Feb 02, 2021 5:33:55 PM FINEST org.springframework.security.web.authentication.AnonymousAuthenticationFilter doFilter

Set SecurityContextHolder to AnonymousAuthenticationToken [Principal=anonymous, Credentials=[PROTECTED], Authenticated=true, Details=WebAuthenticationDetails [RemoteIpAddress=158.167.153.135, SessionId=null], Granted Authorities=[anonymous]]

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @6 org.springframework.security.web.access.ExceptionTranslationFilter@10f7cce2 »

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @7 hudson.security.UnwrapSecurityExceptionFilter@1720f20d »

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @8 jenkins.security.AcegiSecurityExceptionFilter@4688c2db »

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ end: 200

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ end: 200

Feb 02, 2021 5:33:55 PM FINE org.springframework.security.web.context.HttpSessionSecurityContextRepository$SaveToSessionResponseWrapper saveContext

Did not store anonymous SecurityContext

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @8 jenkins.security.AcegiSecurityExceptionFilter@4688c2db « success: 200

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @8 hudson.security.UnwrapSecurityExceptionFilter@1720f20d « success: 200

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @8 org.springframework.security.web.access.ExceptionTranslationFilter@10f7cce2 « success: 200

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @8 org.springframework.security.web.authentication.AnonymousAuthenticationFilter@17950d7f « success: 200

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @8 org.springframework.security.web.authentication.rememberme.RememberMeAuthenticationFilter@61e603f9 « success: 200

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @8 hudson.security.AuthenticationProcessingFilter2@7f0041d « success: 200

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @8 jenkins.security.BasicHeaderProcessor@1813eec9 « success: 200

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @8 hudson.security.HttpSessionContextIntegrationFilter2@3178efbd « success: 200

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @2 hudson.security.ChainedServletFilter@5fbba « success: 200

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @3 org.springframework.security.cas.web.CasAuthenticationFilter@1e8f0ffd « success: 200

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @3 org.jenkinsci.plugins.cas.spring.security.CasSingleSignOutFilter@b129dd3 « success: 200

Feb 02, 2021 5:33:55 PM FINE org.springframework.security.web.context.SecurityContextPersistenceFilter doFilter

Cleared SecurityContextHolder to complete request

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @3 hudson.security.HttpSessionContextIntegrationFilter2@786a250e « success: 200

Feb 02, 2021 5:33:55 PM FINE hudson.security.ChainedServletFilter

/ @2 hudson.security.ChainedServletFilter@4123347 « success: 200

Feb 02, 2021 5:33:56 PM FINER hudson.security.HudsonFilter doFilter

ENTRY

Feb 02, 2021 5:33:56 PM FINE hudson.security.ChainedServletFilter

starting filter on /

Feb 02, 2021 5:33:56 PM FINE hudson.security.ChainedServletFilter

/ @1 hudson.security.ChainedServletFilter@4123347 »

Feb 02, 2021 5:33:56 PM FINE hudson.security.ChainedServletFilter

starting filter on /

Feb 02, 2021 5:33:56 PM FINE hudson.security.ChainedServletFilter

/ @1 hudson.security.HttpSessionContextIntegrationFilter2@786a250e »

Feb 02, 2021 5:33:56 PM FINEST org.springframework.security.web.context.HttpSessionSecurityContextRepository readSecurityContextFromSession

No HttpSession currently exists

Feb 02, 2021 5:33:56 PM FINEST org.springframework.security.web.context.HttpSessionSecurityContextRepository loadContext

Created SecurityContextImpl [Null authentication]

Feb 02, 2021 5:33:56 PM FINE org.springframework.security.web.context.SecurityContextPersistenceFilter doFilter

Set SecurityContextHolder to empty SecurityContext

Feb 02, 2021 5:33:56 PM FINE hudson.security.ChainedServletFilter

/ @2 org.jenkinsci.plugins.cas.spring.security.CasSingleSignOutFilter@b129dd3 »

Feb 02, 2021 5:33:56 PM FINE hudson.security.ChainedServletFilter

/ @3 org.springframework.security.cas.web.CasAuthenticationFilter@1e8f0ffd »

Feb 02, 2021 5:33:56 PM FINEST org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter requiresAuthentication

Did not match request to Ant [pattern='/securityRealm/finishLogin']

Feb 02, 2021 5:33:56 PM FINE org.springframework.security.cas.web.CasAuthenticationFilter serviceTicketRequest

serviceTicketRequest = false

Feb 02, 2021 5:33:56 PM FINE org.springframework.security.cas.web.CasAuthenticationFilter proxyReceptorConfigured

proxyReceptorConfigured = false

Feb 02, 2021 5:33:56 PM FINE org.springframework.security.cas.web.CasAuthenticationFilter proxyReceptorRequest

proxyReceptorRequest = false

Feb 02, 2021 5:33:56 PM FINE org.springframework.security.cas.web.CasAuthenticationFilter proxyTicketRequest

proxyTicketRequest = false

Feb 02, 2021 5:33:56 PM FINE org.springframework.security.cas.web.CasAuthenticationFilter requiresAuthentication

requiresAuthentication = false

Feb 02, 2021 5:33:56 PM FINE hudson.security.ChainedServletFilter

/ end: 200
fcrespel commented 3 years ago

OK, the A granted authority textual representation is required error is here, so it's definitely the empty groups attribute that breaks it. I'll come up with a fix for it :-)

fcrespel commented 3 years ago

A test build is available here. Note that it includes the fixes for #6.

db0 commented 3 years ago

This seems to work well. Good job!

fcrespel commented 3 years ago

CAS plugin version 1.6.0 is now released and includes this fix.