Changes in omni auth strategies/custom auth plugin?

AI-generated summary

The discussion revolves around changes in OmniAuth strategies and custom auth plugins. carlokok shared their custom OAuth2-based authentication code, which recently started failing with a NoMethodError due to raw_info being nil. sam suggested that changes to the internals might have caused the issue and recommended adding more logging to identify the problem.

After debugging, carlokok found that the error occurs on the line uid{ raw_info['id'] }. sam pointed out that raw_info is nil, suggesting that the base class might have renamed it.

Instead of debugging further, carlokok decided to switch to the SSO provider, which works just as well and doesn’t require a special plugin.

We’ve had a custom OAuth2 based authentication which looks like:

require 'auth/oauth2_authenticator'

require 'omniauth-oauth2'
class OmniAuth::Strategies::RoOauth < OmniAuth::Strategies::OAuth2
  SITE_URL = '******'
  # Give your strategy a name.
  option :name, "ro_oauth"

  # This is where you pass the options you would pass when
  # initializing your consumer from the OAuth gem.
  option :client_options, site: SITE_URL

  # These are called after authentication has succeeded. If
  # possible, you should try to set the UID without making
  # additional calls (if the user id is returned with the token
  # or as a URI parameter). This may not be possible with all
  # providers.
  uid{ raw_info['id'] }

  info do
    {
      :name => raw_info['name'],
      :email => raw_info['email'],
      :groups => raw_info['groups']
    }
  end

  extra do
    {
      'raw_info' => raw_info
    }
  end

  def raw_info
    @raw_info ||= access_token.get('*****').parsed
  end
end

class RoAuthenticator < ::Auth::OAuth2Authenticator

  CLIENT_ID = '****'
  CLIENT_SECRET = '****'

  def register_middleware(omniauth)
    omniauth.provider :ro_oauth,
      CLIENT_ID,
      CLIENT_SECRET
  end
  def after_create_account(user, auth)
    super(user, auth)
    data = auth[:extra_data]
    update_user_groups(user, data[:groups])
  end

  def update_user_groups(user, groups)
    grouplist = groups.select { |item| item.starts_with?("beta-") }.map { |item| item[5, item.length - 5] }
    Rails.logger.info "After create account " + grouplist.join(",")
    Group.joins(:users).where(users: { id: user.id } ).each do |c|
      gname = c.name
      if gname.start_with?("beta_")
        gname = gname[5, gname.length - 5]
        if grouplist.include?(gname)
          grouplist.delete(gname) # remove it from the list
        else
          c.group_users.where(user_id: user.id).destroy_all
          # Rails.logger.info "Would remove group " + c.name
        end
      end
    end
    grouplist.each do |c|
       grp = Group.where(name: "beta_" + c).first
       if not grp.nil?
         grp.group_users.create(user_id: user.id, group_id: grp.id)
         # Rails.logger.info "adding user to " + grp.name
       end
    end
  end

  def after_authenticate(auth_token)
    result = Auth::Result.new

    oauth2_provider = auth_token[:provider]
    oauth2_uid = auth_token[:uid]
    data = auth_token[:info]
    result.email = email = data[:email]
    result.name = name = data[:name]

    oauth2_user_info = Oauth2UserInfo.find_by(uid: oauth2_uid, provider: oauth2_provider)

    if !oauth2_user_info && @opts[:trusted] && user = User.find_by_email(email)
      oauth2_user_info = Oauth2UserInfo.create(uid: oauth2_uid,
                                               provider: oauth2_provider,
                                               name: name,
                                               email: email,
                                               user: user)
    end

    result.user = oauth2_user_info.try(:user)
    result.email_valid = @opts[:trusted]

    result.extra_data = {
      uid: oauth2_uid,
      provider: oauth2_provider,
      groups: data[:groups]
    }

    #result

    # result = super(auth_token)
    if not result.user.nil?
      update_user_groups(result.user, result.extra_data[:groups])
    end
    result
  end
end


auth_provider :title => 'Click here to sign in.',
    :message => 'Log in via the main site (Make sure pop up blockers are not enabled).',
    :frame_width => 920,
    :frame_height => 1000,
    :authenticator => RoAuthenticator.new('ro_oauth', trusted: true)

register_css <<CSS

.btn-login.ro_oauth {
  background: #0E76BD;
color: rgb(255, 255, 255);
text-shadow: 0px 1px 0px rgba(0, 0, 0, 0.2);
box-shadow: 0px 1px 0px rgba(255, 255, 255, 0.1) inset;
}

CSS

But it suddenly started failing with:
NoMethodError (undefined method []' for nil:NilClass) /var/www/discourse/plugins/roauth/plugin.rb:23:in block in class:RoOauth’

Did anything change for this, and if yes, what can I do to fix this error?

This would have been a recent fix; since i update almost daily and we only just noticed.

possibly @tgxworld did change some of the internals, what line is failing? Try adding more logging to see where and why it is failing.

it fails on:

  uid{ raw_info['id'] }

I can’t find where I got this sample from though, to compare with, I wrote this before discourse even did docker (and it’s been working fine since), not sure where raw_info has gone to

So raw_info is nil, look at the base class, is it renamed to something else?

thanks I’ll debug a bit more.

Ended up switching to your sso provider instead, works just as well and doesn’t require a special plugin.