postalserver / postal

📮 A fully featured open source mail delivery platform for incoming & outgoing e-mail
https://postalserver.io
MIT License
14.88k stars 1.06k forks source link

"Validation failed: Last name can't be blank" when trying to use OIDC #3049

Open dumbasPL opened 3 months ago

dumbasPL commented 3 months ago

Describe the bug

I'm getting a "Validation failed: Last name can't be blank" exception when trying to use OIDC.

To Reproduce

  1. Configure your OIDC server so that it returns a name without any whitespace
  2. Try to log in using OIDC
  3. Observe crash

Expected behaviour

usernames without whitespace are supported.

Environment details

Temporary workaround for people facing this issue

change the oidc.name_field option to some random value that doesn't exist, doing so will prevent the names from being updated

Additional information/context

the OIDC spec specifies the name field as End-User's full name in displayable form including all name parts, possibly including titles and suffixes, ordered according to the End-User's locale and preferences. so we can't assume that it will be in any particular format. And even if we do, the name field is configurable via the uidc.name_field option and a user might want to use something like preferred_username instead, and that rarely will have any whitespace. The spec also includes given_name, family_name, and middle_name as part of the Standard Claims but not every provider supports them. See: https://openid.net/specs/openid-connect-core-1_0.html#rfc.section.5.1

I have 10+ services configured in my OIDC provider and all of them can handle usernames just fine. Imo assuming anything about the name field is a recipe for disaster. The spec even mentions possibly including titles and suffixes, ordered according to the End-User's locale and preferences., and people all over the world can have different formats, prefixes, suffixes, middle names, etc.

problematic line: https://github.com/postalserver/postal/blob/da90e75036c27482699921613d838f4058a100e7/app/models/user.rb#L127

trace:

[...]
/usr/local/bundle/gems/activerecord-7.0.8.1/lib/active_record/suppressor.rb:54:in `save!'
/opt/postal/app/app/models/user.rb:129:in `find_from_oidc'
/opt/postal/app/app/controllers/sessions_controller.rb:76:in `create_from_oidc'
/usr/local/bundle/gems/actionpack-7.0.8.1/lib/action_controller/metal/basic_implicit_render.rb:6:in `send_action'
[...]

log (details redacted with <REDACTED>):

D, [2024-07-21T17:34:00.071792 #10] DEBUG -- omniauth: (oidc) Callback phase initiated.
2024-07-21 17:34:00 +0000 DEBUG  got auth details from issuer: #<OmniAuth::AuthHash amr=#<Hashie::Array ["pwd", "pop", "hwk", "user", "pin", "mfa"]> at_hash="<REDACTED>" aud=#<Hashie::Array ["postal"]> auth_time=1719762174 azp="postal" client_id="postal" email="nezu@<REDACTED>" email_verified=true exp=1721586840 groups=#<Hashie::Array ["admin", "<REDACTED>"]> iat=1721583240 iss="https://auth.<REDACTED>" jti="<REDACTED>" name="nezu" nonce="<REDACTED>" preferred_username="nezu" sub="<REDACTED>">
2024-07-21 17:34:00 +0000 DEBUG  no user with UID <REDACTED> for issuer https://auth.<REDACTED>
2024-07-21 17:34:00 +0000 DEBUG  found user with e-mail address nezu@<REDACTED> (user ID: 1)
2024-07-21 17:34:00 +0000 ERROR  GET /auth/oidc/callback?code=<REDACTED>&iss=https%3A%2F%2Fauth.<REDACTED>&scope=openid+profile+email+groups&state=<REDACTED> (422) event=request transaction=<REDACTED> controller=SessionsController action=create_from_oidc format=html method=GET path=/auth/oidc/callback?code=<REDACTED>&iss=https%3A%2F%2Fauth.<REDACTED>&scope=openid+profile+email+groups&state=<REDACTED> request_id=<REDACTED> ip_address=<REDACTED> status=422 db_runtime=4.355344772338867 exception_class=ActiveRecord::RecordInvalid exception_message=Validation failed: Last name can't be blank exception_backtrace=/usr/local/bundle/gems/activerecord-7.0.8.1/lib/active_record/validations.rb:80:in `raise_validation_error'\n/usr/local/bundle/gems/activerecord-7.0.8.1/lib/active_record/validations.rb:53:in `save!'\n/usr/local/bundle/gems/activerecord-7.0.8.1/lib/active_record/transactions.rb:302:in `block in save!'\n/usr/local/bundle/gems/activerecord-7.0.8.1/lib/active_record/transactions.rb:354:in `block in with_transaction_returning_status'
2024-07-21 17:34:00 +0000 Rack app ("GET /auth/oidc/callbackcode=<REDACTED>&iss=https%3A%2F%2Fauth.<REDACTED>&scope=openid+profile+email+groups&state=<REDACTED>" - (<REDACTED>)): #<ActiveRecord::RecordInvalid: Validation failed: Last name can't be blank>
willpower232 commented 3 months ago

Yeah definitely should deal with this.

Perhaps also if both first and last name are empty, use the email as one of them so it sort of works?

I'm also not sure how much of the UI relies on both names being present but definitely worth testing.