Module: Sinatra::BrowserID

Defined in:
lib/sinatra/browserid.rb,
lib/sinatra/browserid/helpers.rb,
lib/sinatra/browserid/template.rb

Defined Under Namespace

Modules: Helpers, Templates

Class Method Summary collapse

Class Method Details

.registered(app) ⇒ Object

10 minutes We need to set a global :expires here because of github.com/grosser/cachy/issues/7



28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/sinatra/browserid.rb', line 28

def self.registered(app)
    app.helpers BrowserID::Helpers

    app.set :browserid_url, "https://broker.portier.io"
    app.set :browserid_login_button, :red
    app.set :browserid_login_url, "/_browserid_login"
    app.set :browserid_button_class, ""
    app.set :browserid_button_text, "Log in"

    app.get '/_browserid_login' do
        
    end

  app.post '/_browserid_assert' do
      begin
          # Server checks signature
          # For that, fetch the public key from the LA instance (TODO: Do that beforehand for trusted instances, and generally cache the key)
          public_key_jwks_uri = Addressable::URI.parse(settings.browserid_url + '/keys.json')
          public_key_jwks = ::JSON.parse(URI.parse(public_key_jwks_uri).read)
          public_key = OpenSSL::PKey::RSA.new
          if public_key.respond_to? :set_key
            # We initially set n and d via the then new set_key function, as direct access to n and e is blocked for some ruby and openssl versions.
            # But with OpenSSL 3 this function throws an error, as keys are immutable now. Instead we have to generate the key directly with
            # the right params, as in https://github.com/railslove/epics/issues/138
            sequence = []
            # modulus:
            sequence << OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(UrlSafeBase64.decode64(public_key_jwks["keys"][0]["n"]), 2))
            # exponent:
            sequence << OpenSSL::ASN1::Integer.new(OpenSSL::BN.new(UrlSafeBase64.decode64(public_key_jwks["keys"][0]["e"]), 2))

            public_key = OpenSSL::PKey::RSA.new(OpenSSL::ASN1::Sequence(sequence).to_der)
          else
            public_key.e = OpenSSL::BN.new UrlSafeBase64.decode64(public_key_jwks["keys"][0]["e"]), 2 
            public_key.n = OpenSSL::BN.new UrlSafeBase64.decode64(public_key_jwks["keys"][0]["n"]), 2
          end
          
          id_token = JWT.decode params[:id_token], public_key, true, { :algorithm => 'RS256' }
          id_token = id_token[0]
          # Needs to make sure token is still valid
          if (id_token["iss"] == settings.browserid_url &&
              id_token["aud"] == request.base_url.chomp('/') &&        
              id_token["exp"] > Time.now.to_i &&
              id_token["email_verified"] &&
              # nonce is really known to us
              Cachy.get(id_token["nonce"]))
                  session[:browserid_email] = id_token['email']
                  Cachy.delete_key(id_token["nonce"])
                  session.delete(:nonce)  # it's possible the session persisted
                  if session['redirect_url']
                    redirect session['redirect_url']
                  else
                    redirect "/"
                  end
          else
            # Even when the token check failed the nonce has to be invalidated
            Cachy.delete_key(id_token["nonce"])
            session.delete(:nonce)
          end
      rescue OpenURI::HTTPError => e
          puts "could not validate token: " + e.to_s
      end
      halt 403
      
    end
end