CAS 6.6.x WebAuthn Registration Failing,

293 views
Skip to first unread message

John

unread,
Jan 26, 2023, 1:37:54 PM1/26/23
to CAS Community
When trying to register a new device, the POST request to /webauthn/register is failing from spring security, access denied, http 403.

Commenting out the below within (support/cas-server-support-webauthn-core/src/main/java/org/apereo/cas/webauthn/web/WebAuthnController.java) got it working again,

@PreAuthorize("isAuthenticated()")

Looks like it was added in 6.4.x release, is anyone else not having a registration issue?

Michal Voců

unread,
Jan 31, 2023, 12:16:42 AM1/31/23
to cas-...@apereo.org, John
Hi,
  have you, by any chance, configured spring security for the webauthn endpoint?

Best regards,

Michal Vocu
--
- Website: https://apereo.github.io/cas
- Gitter Chatroom: https://gitter.im/apereo/cas
- List Guidelines: https://goo.gl/1VRrw7
- Contributions: https://goo.gl/mh7qDG
---
You received this message because you are subscribed to the Google Groups "CAS Community" group.
To unsubscribe from this group and stop receiving emails from it, send an email to cas-user+u...@apereo.org.
To view this discussion on the web visit https://groups.google.com/a/apereo.org/d/msgid/cas-user/5ad6db18-8a87-41e9-8216-98f6c1fa8492n%40apereo.org.


Michal Voců

unread,
Feb 3, 2023, 8:11:44 AM2/3/23
to John, CAS Community
Yes, I have the same registration issue.

I thought I have caused this error by meddling with the spring security settings, but it looks like it is not the case.

However, after setting up spring security for the webAuthnDevices actuator like this

spring.security.user.name=XXX
spring.security.user.password=YYY
cas.monitor.endpoints.endpoint.webAuthnDevices.access=AUTHENTICATED

then registration starts to work, but requires HTTP basic authentication.


This is spring security filter chain for /webauthn/register endpoint without any additional configuration:

Security filter chain: [
  ChannelProcessingFilter
  WebAsyncManagerIntegrationFilter
  CorsFilter
  CsrfFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  ExceptionTranslationFilter
  AuthorizationFilter
]
And the chain with the spring security settings as above:
Security filter chain: [
  ChannelProcessingFilter
  WebAsyncManagerIntegrationFilter
  CorsFilter
  CsrfFilter
  BasicAuthenticationFilter
  SecurityContextHolderAwareRequestFilter
  AnonymousAuthenticationFilter
  ExceptionTranslationFilter
  AuthorizationFilter
]

I would say that

  1) setting the actuator access really influences the processing for registration endpoint (and it should not),

  2) using PERMIT or ANONYMOUS is not enough to make it work, as perhaps it does not satisfy the  @PreAuthorize("isAuthenticated()") requirement

I wonder how the registration endpoint should be authenticated; I guess it can not be left unprotected but I fail to see how to set it up.

Regards,

Michal V.

On 1/31/23 16:14, John wrote:
I have nothing configured or defined for endpoints or actuators besides what is default set by cas, we have never used those. I went back and configured according to

management.endpoint.webAuthnDevices.enabled=true
management.endpoints.web.exposure.include=*
cas.monitor.endpoints.endpoint.webAuthnDevices.access=PERMIT

even tried ANONYMOUS below, which makes all actuators work, I can even pull /cas/actuator/webAuthnDevices/username anonymously and gets devices for user. I don't think the endpoint webAuthnDevices controls the end user registration page as it falls under/webauthn/register and NOT /cas/actuator/webAuthnDevices

cas.monitor.endpoints.endpoint.defaults.access=ANONYMOUS

Below is debug output,

2023-01-31 09:05:41,149 DEBUG [org.apereo.cas.web.FlowExecutionExceptionResolver] - <Ignoring the received exception [org.springframework.security.access.AccessDeniedException: Access is denied] due to a type mismatch with handler [org.apereo.cas.webauthn.web.WebAuthnController#startRegistration(String, String, String, boolean, String, HttpServletRequest, HttpServletResponse)]>

And browser POST response to /webauthn/register , base64 decoded is

--- !<java.util.LinkedHashMap>
timestamp: "2023-01-31T15:05:41.161+00:00"
status: 403
error: "Forbidden"
path: "/cas/webauthn/register"

John

unread,
Feb 3, 2023, 8:11:44 AM2/3/23
to CAS Community, micha...@gmail.com, John
I have nothing configured or defined for endpoints or actuators besides what is default set by cas, we have never used those. I went back and configured according to

management.endpoint.webAuthnDevices.enabled=true
management.endpoints.web.exposure.include=*
cas.monitor.endpoints.endpoint.webAuthnDevices.access=PERMIT

even tried ANONYMOUS below, which makes all actuators work, I can even pull /cas/actuator/webAuthnDevices/username anonymously and gets devices for user. I don't think the endpoint webAuthnDevices controls the end user registration page as it falls under/webauthn/register and NOT /cas/actuator/webAuthnDevices

cas.monitor.endpoints.endpoint.defaults.access=ANONYMOUS

Below is debug output,

2023-01-31 09:05:41,149 DEBUG [org.apereo.cas.web.FlowExecutionExceptionResolver] - <Ignoring the received exception [org.springframework.security.access.AccessDeniedException: Access is denied] due to a type mismatch with handler [org.apereo.cas.webauthn.web.WebAuthnController#startRegistration(String, String, String, boolean, String, HttpServletRequest, HttpServletResponse)]>

And browser POST response to /webauthn/register , base64 decoded is

--- !<java.util.LinkedHashMap>
timestamp: "2023-01-31T15:05:41.161+00:00"
status: 403
error: "Forbidden"
path: "/cas/webauthn/register"

On Monday, January 30, 2023 at 11:16:42 PM UTC-6 micha...@gmail.com wrote:

John

unread,
Feb 6, 2023, 10:53:31 PM2/6/23
to CAS Community, micha...@gmail.com, John
Since we don't use any of the actuators, all disabled except for whatever cas sets as default, I am leaving my change by commenting out @PreAuthorize("isAuthenticated()") in WebAuthnController.java. I'm just going along finishing upgrade testing for us and will circle back to this later before we upgrade prod.

However, I do see some changes made below, I haven't had time to test if it will resolve this issue yet, maybe it will be part of next 7.x RC but for now its only in master. If I get some time I will switch to master and give it a go.

John

unread,
Mar 15, 2023, 11:25:47 PM3/15/23
to CAS Community, John, micha...@gmail.com
Circling back to this, it also fails on 7.x current and master. Same issue, I believe I have found the source which is related to the csrf token. It works by excluding the /register from csrf to the ignored endpoints on


with the below,

return List.of(WebAuthnController.BASE_ENDPOINT_WEBAUTHN + WebAuthnController.WEBAUTHN_ENDPOINT_AUTHENTICATE,
                WebAuthnController.BASE_ENDPOINT_WEBAUTHN + WebAuthnController.WEBAUTHN_ENDPOINT_REGISTER);

Frédéric Dussurget

unread,
Mar 23, 2023, 3:51:11 PM3/23/23
to CAS Community, John, micha...@gmail.com
Hi, I've got quite the same issue : it works perfectly with CAS 6.5.9 but not on 6.6 nor on the master branch 7.x.
On 6.6, after basic auth, a popup asks for the Yubikey pin and then, when I press the register button,the flow breaks at POST https://xxxxxxx.xx/cas/webauthn/register/finish. (FF : err 400 strict-origin-when-cross-origin)

(The service app I use for my tests is the same when I wetn thru every CAS version)

webAuthnDevices.acces endpoint is AUTHENTICATED in my cas.yml just as you did

here is my build.gradle webauthn section :
   // MFA FIDO2 WEBAUTHN
    implementation "org.apereo.cas:cas-server-support-webauthn:${project.'cas.version'}"
    implementation "org.apereo.cas:cas-server-support-webauthn-redis:${project.'cas.version'}"
    implementation "org.apereo.cas:cas-server-support-webauthn-core:${project.'cas.version'}" (this one in order to comment out  @PreAuthorize("isAuthenticated()") as you did in  src/main/java/org/apereo/cas/webauthn/web/WebAuthnController.java )

    //MFA TRUSTED DEVICE
    implementation "org.apereo.cas:cas-server-support-trusted-mfa:${project.'cas.version'}"
    implementation "org.apereo.cas:cas-server-support-trusted-mfa-redis:${project.'cas.version'}"

(John, what are the extra dependencies that you implement in your build.gradle cas overlay to be able to modify the src/main/java/org/apereo/cas/config/WebAuthnConfiguration.java ? Compilation breaks)

Regards,

John

unread,
Mar 23, 2023, 11:57:51 PM3/23/23
to CAS Community, dussu...@gmail.com, John, micha...@gmail.com
Spring security and probably one or 2 of the webauthn, I dont remeber at the moment with looking at local commit history but here is all from gradle,


/** Core **/
    implementation "org.apereo.cas:cas-server-core-api-configuration-model"
    implementation "org.apereo.cas:cas-server-core-api-mfa"
    implementation "org.apereo.cas:cas-server-core-events-configuration"
    implementation "org.apereo.cas:cas-server-core-notifications"
    implementation "org.apereo.cas:cas-server-core-authentication"
    implementation "org.apereo.cas:cas-server-core-authentication-api"
    implementation "org.apereo.cas:cas-server-core-authentication-mfa-api"
    implementation "org.apereo.cas:cas-server-core-util"
    implementation "org.apereo.cas:cas-server-core-web-api"
    implementation "org.apereo.cas:cas-server-core-webflow"
    implementation "org.apereo.cas:cas-server-core-webflow-api"
    implementation "org.apereo.cas:cas-server-core-webflow-mfa-api"
    implementation "org.apereo.cas:cas-server-webapp"
    implementation "org.apereo.cas:cas-server-webapp-init"
    implementation "org.apereo.cas:cas-server-webapp-config"

    /** Rest Plugins **/
    implementation "org.apereo.cas:cas-server-support-configuration-cloud-rest"
    implementation "org.apereo.cas:cas-server-support-rest-authentication"

    /** LDAP Support **/
    implementation "org.apereo.cas:cas-server-support-ldap"
    implementation "org.apereo.cas:cas-server-support-pm-ldap"
    implementation "org.apereo.cas:cas-server-support-pm-rest"

    /** Database Support **/
    implementation "org.apereo.cas:cas-server-support-jdbc"
    implementation "org.apereo.cas:cas-server-support-jpa-util"
    implementation "mysql:mysql-connector-java:${project.mysqlVerison}"
    implementation "com.microsoft.sqlserver:mssql-jdbc:${project.mssqlVersion}"

    /** Interrupt Support **/
    implementation "org.apereo.cas:cas-server-support-interrupt-webflow"

    /** Multifactor Auth **/
    implementation "org.apereo.cas:cas-server-support-gauth"
    implementation "org.apereo.cas:cas-server-support-gauth-ldap"
    implementation "org.apereo.cas:cas-server-support-webauthn"
    implementation "org.apereo.cas:cas-server-support-webauthn-ldap"
    implementation "org.apereo.cas:cas-server-support-webauthn-core"
    implementation "org.apereo.cas:cas-server-support-webauthn-core-webflow"
    implementation "org.apereo.cas:cas-server-support-simple-mfa"
    implementation "org.apereo.cas:cas-server-support-trusted-mfa"

    /** Protocols **/
    implementation "org.apereo.cas:cas-server-support-ws-idp"
    implementation "org.apereo.cas:cas-server-support-saml-idp"
    implementation "org.apereo.cas:cas-server-support-saml-sp-integrations"


    /** Services **/
    /** implementation "org.apereo.cas:cas-server-support-json-service-registry" **/
    implementation "org.apereo.cas:cas-server-support-rest-service-registry"

    implementation "org.springframework.security:spring-security-config:5.7.3"
    implementation "commons-net:commons-net:${project.apacheNetCom}"

Frédéric Dussurget

unread,
Mar 29, 2023, 5:29:34 AM3/29/23
to CAS Community, John, Frédéric Dussurget, micha...@gmail.com
Thank you, you saved me lots of time, actually I needed those two :
    implementation "org.springframework.security:spring-security-config"
    implementation "org.springframework.security:spring-security-web"

But I still have an js issue (JSON.Parse) when registering my device :

"Registration failed SyntaxError: JSON.parse: unexpected non-digit at line 1 column 2 of the JSON data" after the POST request on https://cas-xx.xxx.fr/cas/webauthn/register.
(Chrome says the same: Registration failed SyntaxError: No number after minus sign in JSON at position 1.)

The error is caught here :
# register https://cas-xx.xxxxxx.fr/cas/js/webauthn/webauthn.js:477.
# (Asynchrone : promise callback) / register https://cas-xx.xxxx.fr/cas/js/webauthn/webauthn.js:475
# https://cas-xx.xxxxxx.fr/cas/login?service=https://node-cas-xxxxx.addomain.xxxxxxx.fr:9446/sample/&renew=true:390.

(The webapp is an instance of cas-sample-java-webapp running on port 9446.)

About JSON.Parse :
https://xxxxcas/login?service=https://xxxxx:9446/sample/&renew=true at lines 386 and 390 : register(username, displayName, credentialNickname, csrfToken);

In my browser debugger, data seems present, as I can see them parsed by the function getRegisterRequest in webauthn.js line 327:

arguments: Arguments
0: {…}
authenticate: "webauthn/authenticate"
register: "webauthn/register"
<prototype>: {…}
1: "frederic.dussurget"
2: "Frederic Dussurget"
3: "wonderful_borg"
4: false
callee:
length: 5
Symbol(Symbol.iterator):values()
<get callee()>: ()
<set callee()>: ()
<prototype>: {…
credentialNickname: "wonderful_borg"
displayName: "Frederic Dussurget"
requireResidentKey: false
urls: {…}
authenticate: "webauthn/authenticate"
register: "webauthn/register"
<prototype>: {…}
username: "frederic.dussurget"

I you guys have any idea ...
Regards,

John

unread,
Mar 29, 2023, 10:15:00 AM3/29/23
to CAS Community, dussu...@gmail.com, John, micha...@gmail.com
What does your cas.log state for error? Are you using a valid ssl certificate, cas host name matches whats in config? Also, in 7.x/master you have to edit this,


with the below,

return List.of(WebAuthnController.BASE_ENDPOINT_WEBAUTHN + WebAuthnController.WEBAUTHN_ENDPOINT_AUTHENTICATE,
                WebAuthnController.BASE_ENDPOINT_WEBAUTHN + WebAuthnController.WEBAUTHN_ENDPOINT_REGISTER);

There's actually 2 bugs, maybe more. One is the PreAuthorize and the other is CSRF related to spring 6/spring boot 3 and possible another bug. I fixed the csrf issue and still working through the other as time permits.

Frédéric Dussurget

unread,
Apr 6, 2023, 7:59:11 AM4/6/23
to CAS Community, John, Frédéric Dussurget, micha...@gmail.com

Hi,
I'm now able to register my webauthn device, to login, and trust my device.

What I noticed is that the allowed-origins (device registering) property and application-id extension (connect) seem now mandatory to me, (though it was not in 6.5.9).
Without those two settings, I'm stuck.

      web-authn:
        core:
          relying-party-id: mydomain.fr
          relying-party-name: myrpname
          allowed-origins: https://cas-dev.mydomain.fr
          trusted-device-enabled: true
          application-id: https://cas-dev.mydomain.fr/test


First, I want to say that I thank you all for your precious advices ! (@PreAuthorize("isAuthenticated()") + WebAuthnConfiguration.java trick)
This won't go in production right now, because I wonder about the security impact when accessing the webauthn/register endpoint ... ?

Regards,

Graham Ballantyne

unread,
May 12, 2023, 4:07:06 AM5/12/23
to CAS Community, dussu...@gmail.com, John, micha...@gmail.com
Hi all,

I'm having a similar issue with webauthn device registration failing on CAS 6.6.x; the /cas/webauthn/register endpoint returns a 403 error, and the server logs have an invalid CSRF token error:

web_1  | 2023-05-11 23:11:38,248 DEBUG [org.springframework.security.web.access.channel.ChannelProcessingFilter] - <Request: filter invocation [POST /webauthn/register]; ConfigAttributes: [REQUIRES_SECURE_CHANNEL]>
web_1  | 2023-05-11 23:11:38,250 DEBUG [org.springframework.security.web.csrf.CsrfFilter] - <Invalid CSRF token found for https://cas_server/cas/webauthn/register>
web_1  | 2023-05-11 23:11:38,250 DEBUG [org.springframework.security.web.access.AccessDeniedHandlerImpl] - <Responding with 403 status code>

I'm not able to implement the workaround here (commenting out @PreAuthorize("isAuthenticated()") in WebAuthnController.java) as WebAuthnController.java no longer contains that line. It looks like Misagh changed how this works in a recent commit (https://github.com/apereo/cas/commit/b9233b0731004fdc85994539c67fe0cd0f01c2c3).

I've tried adding the cas.authn.mfa.web-authn.core.allowed-origins property (which the docs say defaults to the server name, so I'd think it wouldn't be necessary) and it still fails. My webauthn settings from cas.properties are:

cas.authn.mfa.web-authn.core.application-id=https://mycasdomain.ca
cas.authn.mfa.web-authn.core.relying-party-name=Graham CAS Dev
cas.authn.mfa.web-authn.core.relying-party-id=mycasdomain.ca
cas.authn.mfa.web-authn.core.display-name-attribute=displayName
cas.authn.mfa.web-authn.core.allow-primary-authentication=true
cas.authn.mfa.web-authn.core.allow-untrusted-attestation=true
cas.authn.mfa.web-authn.core.trusted-device-enabled=true
cas.authn.mfa.web-authn.crypto.encryption.key=xxx
cas.authn.mfa.web-authn.crypto.signing.key=yyy
cas.authn.mfa.web-authn.core.allowed-origins:https://mycasdomain.ca

I'm not a Java developer so I'm a little out of my element in trying to see where the problem is. Any tips would be appreciated!

Cheers,
Graham.

Frédéric Dussurget

unread,
May 12, 2023, 9:21:53 AM5/12/23
to Graham Ballantyne, CAS Community, John, micha...@gmail.com
Hi Graham,

I gave it a try this morning (but on branch master 7.0.0-SNAPSHOT) and ... it's eventually working great :) Thanks to Misagh and the dev team !

What I've done is removing every workaround we did on this topic : removed config/WebAuthnConfiguration.java + webauthn/web/WebAuthnController.java, removed the extra pack of deps linked to those two files, flushed my dev db and imported just one mfa-webauthn service, removed custom theme and finally recompiled and restarted tomcat10 (mine is not bundled, it is marked as external thru gradle.properties). I can now register my fido2 device and then login without any error.

build.gradle linked deps :

    // MFA FIDO2 WEBAUTHN
    implementation "org.apereo.cas:cas-server-support-webauthn:${project.'cas.version'}"
    implementation "org.apereo.cas:cas-server-support-webauthn-redis:${project.'cas.version'}"


cas.yml :

      web-authn:
        core:
          relying-party-id: mydomain.fr
          relying-party-name: mynickname
          allowed-origins: https://cas.mydomain.fr
          trusted-device-enabled: false
          application-id: https://www.mydomain.fr


Frédéric Dussurget

unread,
May 12, 2023, 9:21:53 AM5/12/23
to Graham Ballantyne, CAS Community, John, micha...@gmail.com
I forgot, here is what I have about endpoints spring security management in cas.yml :

  monitor:
    endpoints:
      endpoint:
        defaults:
          access: AUTHENTICATED
        health:
          access: IP_ADDRESS
          requiredIpAddresses: xx.yy.www.zz, aa.bb.cc.dd,etc.
[...]
        registeredServices:
          access: IP_ADDRESS
          requiredIpAddresses:  xx.yy.www.zz, aa.bb.cc.dd,etc.
        importRegisteredServices:
          access: IP_ADDRESS
          requiredIpAddresses:  xx.yy.www.zz, aa.bb.cc.dd,etc.
[...]
management:
  endpoints:
    web:
      exposure:
        include: '*'
    enabled-by-default: true

Graham Ballantyne

unread,
May 13, 2023, 4:43:39 AM5/13/23
to Frédéric Dussurget, CAS Community, John, micha...@gmail.com
Hi Frédéric,

Thanks for replying! I'm not in a position right now to try with the 7.0 RC. I'm still getting the error on 6.6.x. I have the following set in my cas.properties:

management.endpoint.webAuthnDevices.enabled=true
management.endpoints.web.exposure.include=*
management.endpoints.web.enabled-by-default: true
cas.monitor.endpoints.endpoint.webAuthnDevices.access=PERMIT

I'm not using tomcat; I'm running this in a docker container in my dev environment directly from `java -server -jar cas.war`.

– Graham
Reply all
Reply to author
Forward
0 new messages