Skip to content
This repository has been archived by the owner on Jul 19, 2024. It is now read-only.

Returned nonce did not match. #22

Open
EDeijl opened this issue Jun 14, 2016 · 11 comments
Open

Returned nonce did not match. #22

EDeijl opened this issue Jun 14, 2016 · 11 comments

Comments

@EDeijl
Copy link

EDeijl commented Jun 14, 2016

When I try to login using activedirectory I get the follow error and stacktrace:

JWT::DecodeError (Returned nonce did not match.):
omniauth-azure-activedirectory (1.0.0) lib/omniauth/strategies/azure_activedirectory.rb:289:in   `validate_and_parse_id_token'
omniauth-azure-activedirectory (1.0.0) lib/omniauth/strategies/azure_activedirectory.rb:92:in `callback_phase'
omniauth (1.3.1) lib/omniauth/strategy.rb:227:in `callback_call'
omniauth (1.3.1) lib/omniauth/strategy.rb:184:in `call!'
omniauth (1.3.1) lib/omniauth/strategy.rb:164:in `call'
omniauth (1.3.1) lib/omniauth/strategy.rb:408:in `call_app!'
omniauth (1.3.1) lib/omniauth/strategy.rb:362:in `callback_phase'
omniauth-azure-activedirectory (1.0.0) lib/omniauth/strategies/azure_activedirectory.rb:94:in `callback_phase'
omniauth (1.3.1) lib/omniauth/strategy.rb:227:in `callback_call'
omniauth (1.3.1) lib/omniauth/strategy.rb:184:in `call!'
omniauth (1.3.1) lib/omniauth/strategy.rb:164:in `call'
omniauth (1.3.1) lib/omniauth/builder.rb:63:in `call'
warden (1.2.6) lib/warden/manager.rb:35:in `block in call'
warden (1.2.6) lib/warden/manager.rb:34:in `catch'
warden (1.2.6) lib/warden/manager.rb:34:in `call'

It fails here https://github.com/AzureAD/omniauth-azure-activedirectory/blob/master/lib/omniauth/strategies/azure_activedirectory.rb#L289

I'm trying to use ominauth-azure_activedirectory in combination with Devise, my config looks like this:

  config.omniauth :azure_activedirectory, ENV['AAD_CLIENT_ID'], ENV['AAD_TENANT']

Is my setup wrong? Or is it a bug in this library?

@adammartin-mednax
Copy link

I am also receiving this bug On the exact same line ... any update on this?

@adammartin
Copy link

Additional note: Very odd behavior I have just uncovered. I seem to be able to reproduce problem in Safari and Chrome but not in Firefox ... This is very confusing!

@adammartin
Copy link

Ok I found a workaround. The fact that browsers seemed to be the variance I guessed it was tied to cookies.

I changed the code and added the following:

use Rack::Session::Cookie,
:key => 'rack.session',
:path => '/',
:expire_after => 14400,
:secret => 'your_secret_goes_here'

This seems to work just fine!

@brentschmaltz
Copy link
Member

@adammartin is 'your_secret_goes_here' the nonce (or nonce related)?

@dunyakirkali
Copy link

dunyakirkali commented Feb 3, 2017

@adammartin Setting Rails to use Rack::Session::Cookie in application.rb seems to help indeed.

module RailsApp
  class Application < Rails::Application
    config.middleware.use Rack::Session::Cookie, key: 'rack.session', path: '/', expire_after: 14400, secret: ENV['SECRET_KEY_BASE']
  end
end

@aymebou
Copy link

aymebou commented Aug 31, 2018

I have the same issue here, anyone has a solution using rails's ActionDispatch::Session::CookieStore ? Do I have to use rack ?

Edit : worked fine with
config.middleware.use ActionDispatch::Cookies
config.middleware.use ActionDispatch::Session::CookieStore
in application.rb

@pierre-pretorius
Copy link

I tested and found the session[:session_id] is different once Azure AD redirects back to your application, but not if you have FireFox. Perhaps security adjustments were made to Chrome and other browsers to reset the session in some cases?

If you are using Rails, this patch should solve the problem and doesn't require messing with middleware. Note the patch is based on the more popular fork of this repo. Although it seems long it actually replaces very little code.

Gemfile:

gem 'omniauth-azure-activedirectory', github: 'planio-gmbh/omniauth-azure-activedirectory

Create file config/initializers/azure_ad_patch.rb:

#
# The original gem writes and reads the nonce from the session.  This works on firefox but not on chrome where the session
# is reset for an unknown reason once you the user is redirected from Azure back to the application.  This patch places the
# nonce in the Rails cache which should still be secure since the purpose of a nonce is "number used once" which is still
# the case with this patch.
#
OmniAuth::Strategies::AzureActiveDirectory.class_eval do
  def nonce_cache_key(nonce)
    "omniauth_azure_activedirectory:nonce:#{nonce}"
  end

  def claim_nonce!(nonce)
    if Rails.cache.read(nonce_cache_key(nonce))
      Rails.cache.delete(nonce_cache_key(nonce))
      true
    else
      false
    end
  end

  def new_nonce
    nonce = SecureRandom.uuid
    Rails.cache.write(nonce_cache_key(nonce), true, expires_in: 7.days)
    nonce
  end

  def validate_and_parse_id_token(id_token)
    # The second parameter is the public key to verify the signature.
    # However, that key is overridden by the value of the executed block
    # if one is present.
    #
    # If you're thinking that this looks ugly with the raw nil and boolean,
    # see https://github.com/jwt/ruby-jwt/issues/59.
    jwt_claims, jwt_header =
      JWT.decode(id_token, nil, true, verify_options) do |header|
        # There should always be one key from the discovery endpoint that
        # matches the id in the JWT header.
        unless key = signing_keys.find{|k|
          k['kid'] == header['kid']
        }
          fail JWT::VerificationError, 'No keys from key endpoint match the id token'
        end

        # The key also contains other fields, such as n and e, that are
        # redundant. x5c is sufficient to verify the id token.
        if x5c = key['x5c'] and !x5c.empty?
          OpenSSL::X509::Certificate.new(JWT::Base64.url_decode(x5c.first)).public_key
          # no x5c, so we resort to e and n
        elsif exp = key['e'] and mod = key['n']
          key = OpenSSL::PKey::RSA.new
          mod = openssl_bn_for mod
          exp = openssl_bn_for exp
          if key.respond_to? :set_key
            # Ruby 2.4 ff
            key.set_key mod, exp, nil
          else
            # Ruby < 2.4
            key.e = exp
            key.n = mod
          end
          key.public_key
        else
          fail JWT::VerificationError, 'Key has no info for verification'
        end
      end
    return jwt_claims, jwt_header if claim_nonce!(jwt_claims['nonce'])
    fail JWT::DecodeError, 'Returned nonce did not match.'
  end
end

@drakkhen
Copy link

drakkhen commented Aug 19, 2021

Did some googling and tinkering a bit today, and I really like the solution that @pierre-pretorius suggested. It works without having to set SameSite to :none on the session cookie.

In order to work in development though, you will need to run bundle exec rails dev:cache, which may not be desirable. I'm wondering if the patch could be modified to handle that some other way when Rails.application.config.action_controller.perform_caching is false (perhaps using Pstore ...is there a better option?).

I also don't know where to submit a patch. @microsoft / @AzureAD doesn't seem to care about this repo of theirs, and according to @davevanfleet's comment on #54, @planio-gmbh's fork is no longer super active, either.

@davevanfleet
Copy link

If you submit a PR on my repo I'm happy to merge it in. I don't mind maintaining the repo (but could probably use some help updating the original tests, since most of them are currently failing after updating the dependencies to allow this to work with the more up-to-date google omniauth gem - once the tests and CI/CD are back up and running smoothly maintaining the repo will be fine).
https://github.com/davevanfleet/omniauth-activedirectory

mbkloster added a commit to gitclear/omniauth-azure-activedirectory that referenced this issue May 17, 2022
…ivedirectory#22, in the interest of eliminating "Returned nonce did not match" errors
@pulkit110
Copy link

This happens with Rails 6.1+ because it uses a SameSite policy for cookies by default. This can be bypassed for AD authentication by adding the following to your application.rb:

config.action_dispatch.cookies_same_site_protection = lambda { |request|
  # No SameSite attribute for azureactivedirectory since it uses
  # session cookie to send a nonce and verify it on the callback.
  return if request.fullpath.include?("azureactivedirectory")

  :lax
}

This works without having to use any other workarounds or patching the strategy to use cache.

@jaspertandy
Copy link

@pulkit110 I feel like you just saved half a day of my life with this - thank you.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests