SAML-Toolkits / ruby-saml

SAML SSO for Ruby
MIT License
919 stars 569 forks source link

Can't update ruby-saml under older rubies #722

Open ilikepi opened 1 month ago

ilikepi commented 1 month ago

We have an existing app running with an older version of ruby and ruby-saml, integrated with omniauth-saml and devise. We're in the middle of the long incremental process to modernize it, and we are currently trying to update ruby-saml to address the recent critical vulnerability, but we're having a problem. No matter what I do, bundler refuses to install ruby-saml 1.17.0 under ruby 2.3.

If I try updating the version specified in my Gemfile and then running bundle update ruby-saml, I get the following:

% bundle update ruby-saml
Fetching gem metadata from https://rubygems.org/...........
Fetching gem metadata from https://rubygems.org/.
Resolving dependencies...
Bundler could not find compatible versions for gem "nokogiri":
  In Gemfile:
    nokogiri (= 1.10.10)

    ruby-saml (= 1.17.0) was resolved to 1.17.0, which depends on
      nokogiri (>= 1.13.10)

If I manually update Gemfile.lock to try to bypass Bundler's dependecy resolution, I get this error instead:

% bundle install
[...snip...]
Using omniauth 1.3.2
Fetching rexml 3.2.5
Installing rexml 3.2.5
Fetching ruby-saml 1.17.0
Downloading ruby-saml-1.17.0 revealed dependencies not in the API or the
lockfile (nokogiri (>= 1.13.10)).
Either installing with `--full-index` or running `bundle update ruby-saml`
should fix the problem.

Notably, these errors occur outside of our app as well. Under ruby 2.3, rubygems 3.3.26, and bundler 2.3.26, the following minimal Gemfile fails with an error roughly equivalent to the first one above:

# frozen_string_literal: true

source 'https://rubygems.org'

ruby '2.3.8'

gem 'ruby-saml', '1.17.0'

...and instead I get something more like the second error above if I add this minimal lockfile:

GEM
  remote: https://rubygems.org/
  specs:
    mini_portile2 (2.4.0)
    nokogiri (1.10.10)
      mini_portile2 (~> 2.4.0)
    ruby-saml (1.17.0)
      nokogiri (>= 1.10.10, < 1.11.0)

PLATFORMS
  x86_64-linux

DEPENDENCIES
  ruby-saml (= 1.17.0)

RUBY VERSION
   ruby 2.3.8p459

BUNDLED WITH
   2.3.26

I tried similar experiments under ruby 2.5, but I got similar results.

In researching this issue, I did find #588, but the blog entry referenced in that issue doesn't provide any advice beyond "try updating the lockfile by hand", which as I mentioned has not helped.

Looking at the gemfile, the errors I quoted above suggest that bundler is hitting the else clause at https://github.com/SAML-Toolkits/ruby-saml/blob/v1.17.0/ruby-saml.gemspec#L57C1-L60C6 when trying to build runtime dependencies based on RUBY_VERSION. I don't know enough about the inner workings of bundler to guess at why it's doing that though...

EDIT: minor clarification

ilikepi commented 1 month ago

Interesting twist: I tried switching to a :git source to see if that would be sufficient to cause Bundler to take a different path for dependency resolution, and...it worked. Here's a minimal Gemfile that installs successfully under ruby 2.3.8, rubygems 2.5.2.3 (included with ruby 2.3.8), and bundler 1.17.3:

# frozen_string_literal: true

source 'https://rubygems.org'

ruby '2.3.8'

gem 'ruby-saml', :git => 'https://github.com/SAML-Toolkits/ruby-saml.git',
                 :tag => 'v1.17.0'

I was able to use the same trick in my application's Gemfile. At the very least, this confirms that my manually updated Gemfile.lock was syntactically correct. It doesn't help me understand the errors I reported earlier, but at least I can move our application forward...

pitbulk commented 1 month ago

@ilikepi I also delivered 1.12.3 in case to cover those very old projects using ruby-saml.

Glad you were able to solve your use case by using code from Github rather than from Rubygems.

ilikepi commented 1 month ago

Thanks, I did see that 1.12.3 was available, but I wanted to be current if possible in our application.

I see that there are CI runs for which 1.17.0 passed under old ruby versions, but I don't really know anything about how that works to be able to figure out how the CI environment differs from my own local environment.

EDIT: I guess the main and probably critical difference is that the CI run doesn't actually need to install the ruby-saml gem, since it's running in the equivalent of a checked out repo.