As far as I can tell, omniauth-saml has no way to say if an email address provided via SAML is "verified". However, I would be strongly surprised if anyone is using SAML authentication in a context where the provided email _could_ be unverified.
This means that after authentication with SAML, the user is taken to an email confirmation form, which contains a placeholder email (e.g. [email protected]).
I would suggest that email addresses from SAML (and potentially other authentication strategies) should always be treated as "verified".
cc @moritzheiber
Coming from a background where SAML is usually used for authenticaten I can say that almost all providers are treating the information supplied by the SAML authority as verified. This makes sense.
Piping in @gloaec as they used to be the original author of the SAML PR #3148
@ineffyble, @moritzheiber, You are right. Using either CAS or SAML, users usually come from some existing directory (ex: LDAP, ActiveDirectory, etc..). So the email is supposed to be verified from the moment it exists. However, there are scenarios for which the user does not authenticate with his email (username instead for exemple) and the email attribute is not always returned by the IDP. So, here is how it works :
We check if the user exists with provided email if the provider gives us a verified email. If no verified email was provided or the user already exists, we assign a temporary email and ask the user to verify it on the next step via Auth::ConfirmationsController.finish_signup
app/models/concerns/omniauthable.rb (User)
module Omniauthable
TEMP_EMAIL_REGEX = /\Achange@me/
def email_verified?
email && email !~ TEMP_EMAIL_REGEX
end
def create_for_oauth(auth)
email_is_verified = auth.info.email && (auth.info.verified || auth.info.verified_email)
email = auth.info.email if email_is_verified && !User.exists?(email: auth.info.email)
user = User.new(
email: email ? email : "#{TEMP_EMAIL_PREFIX}-#{auth.uid}-#{auth.provider}.com",
)
end
end
app/controllers/auth/omniauth_callback_controller.rb
def after_sign_in_path_for(resource)
if resource.email_verified?
root_path
else
finish_signup_path
end
end
The finish_signup_path is a simple form where the user will be asked for his actual email after sign in via Oauth. When he submits the form, he will then receive a confirmation mail. If the user clicks on the confirmation link, then his email will be updated in mastodon.
Nevertheless, a user with or without a verified email can sign in. From my guessing, mastodon relies on the user's confirmed? attribute to grant access to the application. email_verified? attribute was introduced with the Oauth strategy and none of mastodon mechanisms makes use of it for now. But maybe it should in order to restrict access to verified emails only. I let @Gargron and @immae give their opnion about this.
I hope this helps. Cheers !
@gloaec
we ask the user to verify it on the next step
That might be the intent, but in actuality the next step displays the temp email generated in the code above - the #{TEMP_EMAIL_PREFIX}-#{auth.uid}-#{auth.provider}.com - so it's asking them to confirm an invalid email, which they have to clear and then manually type out.
I think in an "enterprisey" context, you wouldn't want users having to click a verification email once they've logged in for the first time.
if the provider gives us a verified email
How can the SAML provider give a "verified" email? I can't see anything in omniauth-saml that would pass such a parameter?
@ineffyble
info hash. TEMP_EMAIL_REGEX to not display the emails that match change@me....omniauth-saml README : :attribute_statements - Used to map Attribute Names in a SAMLResponse to entries in the OmniAuth info hash. For example, if your SAMLResponse contains an Attribute called EmailAddress, specify {:email => ['EmailAddress']} to map the Attribute to the corresponding key in the info hash. URI-named Attributes are also supported, e.g. {:email => ['http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress']}. Note: All attributes can also be found in an array under auth_hash[:extra][:raw_info], so this setting should only be used to map attributes that are part of the OmniAuth info hash schema.
However, if you are using docker, I didn't handle this use-case scenario in the config :
config/initializers/omniauth.rb
saml_options[:attribute_statements] = {}
saml_options[:attribute_statements][:uid] = [ENV['SAML_ATTRIBUTES_STATEMENTS_UID']] if ENV['SAML_ATTRIBUTES_STATEMENTS_UID']
saml_options[:attribute_statements][:email] = [ENV['SAML_ATTRIBUTES_STATEMENTS_EMAIL']] if ENV['SAML_ATTRIBUTES_STATEMENTS_EMAIL']
saml_options[:attribute_statements][:full_name] = [ENV['SAML_ATTRIBUTES_STATEMENTS_FULL_NAME']] if ENV['SAML_ATTRIBUTES_STATEMENTS_FULL_NAME']
You should add something like :
saml_options[:attribute_statements][:verified] = [ENV['SAML_ATTRIBUTES_STATEMENTS_VERIFIED']] if ENV['SAML_ATTRIBUTES_STATEMENTS_VERIFIED']
saml_options[:attribute_statements][:verified_email] = [ENV['SAML_ATTRIBUTES_STATEMENTS_VERIFIED_EMAIL']] if ENV['SAML_ATTRIBUTES_STATEMENTS_VERIFIED_EMAIL']
Match with your SAML attributes (here attributes are encrypted)
.env.production :
SAML_ATTRIBUTES_STATEMENTS_UID="urn:oid:0.9.2342.19200300.100.1.1"
SAML_ATTRIBUTES_STATEMENTS_EMAIL="urn:oid:1.3.6.1.4.1.5923.1.1.1.6"
SAML_ATTRIBUTES_STATEMENTS_FULL_NAME="urn:oid:2.5.4.42"
SAML_ATTRIBUTES_STATEMENTS_VERIFIED="<is_verified_attr_key>"
SAML_ATTRIBUTES_STATEMENTS_VERIFIED="<verified_email_attr_key>"
Then, configure your IDP metadatas accordingly to actually send this info.
Hope this helps.
@gloaec
There is an email attribute set and working, but I'll double check.
My take from reading the code for create_for_oauth was that even if an email is passed in the info hash, if the email passed in wasn't "verified", it was lost, and the dummy email was what is saved to the DB and read on the next step/form. finish_signup.html.haml just uses user.email.
I see your point about adding new attributes, however:
@ineffyble
There is an email attribute set and working, but I'll double check.
Yeah, careful though, if you enable encryption, the keys shall be encrypted as well as I remember.
I'm just giving you the details of how it works for the time being (and that suited my needs). But you are totally right, we could just add some more configuration option that allows us to assume that the email if verified no matter what. PR welcome ;)
@gloaec I鈥檓 probably wrong, but I can鈥檛 see any way the finish_signup form would ever load with an actual email address in it.
I changed my comment up there :)
https://github.com/tootsuite/mastodon/issues/6533#issuecomment-367755367
Ah, cool, I鈥檓 not completely mad then :)
That was how it worked in my head tho :p
I'll fix this, because this is definitely a bug.
Most helpful comment
That was how it worked in my head tho :p
I'll fix this, because this is definitely a bug.