Skip to content
Extraits de code Groupes Projets
authorizations_controller_spec.rb 9,34 ko
Newer Older
  • Learn to ignore specific revisions
  • Augier's avatar
    Augier a validé
    require "spec_helper"
    
    theworldbright's avatar
    theworldbright a validé
    describe Api::OpenidConnect::AuthorizationsController, type: :controller do
    
    augier's avatar
    augier a validé
      let!(:client) do
    
    theworldbright's avatar
    theworldbright a validé
        Api::OpenidConnect::OAuthApplication.create!(
    
    augier's avatar
    augier a validé
          client_name: "Diaspora Test Client", redirect_uris: ["http://localhost:3000/"])
    
    augier's avatar
    augier a validé
      end
    
    Augier's avatar
    Augier a validé
      let!(:client_with_multiple_redirects) do
    
    theworldbright's avatar
    theworldbright a validé
        Api::OpenidConnect::OAuthApplication.create!(
    
    augier's avatar
    augier a validé
          client_name: "Diaspora Test Client", redirect_uris: ["http://localhost:3000/", "http://localhost/"])
    
    Augier's avatar
    Augier a validé
      end
    
      # TODO: jhass - "Might want to setup some factories in spec/factories.rb, see factory_girl's docs."
    
    
      before do
        sign_in :user, alice
        allow(@controller).to receive(:current_user).and_return(alice)
      end
    
      describe "#new" do
    
        context "when not yet authorized" do
          context "when valid parameters are passed" do
            render_views
            context "as GET request" do
              it "should return a form page" do
                get :new, client_id: client.client_id, redirect_uri: "http://localhost:3000/", response_type: "id_token",
                    scope: "openid", nonce: SecureRandom.hex(16), state: SecureRandom.hex(16)
                expect(response.body).to match("Diaspora Test Client")
              end
            end
    
            context "as POST request" do
              it "should return a form page" do
                post :new, client_id: client.client_id, redirect_uri: "http://localhost:3000/", response_type: "id_token",
                     scope: "openid", nonce: SecureRandom.hex(16), state: SecureRandom.hex(16)
                expect(response.body).to match("Diaspora Test Client")
              end
    
          context "when client id is missing" do
            it "should return an bad request error" do
              post :new, redirect_uri: "http://localhost:3000/", response_type: "id_token",
    
    Augier's avatar
    Augier a validé
                   scope: "openid", nonce: SecureRandom.hex(16), state: SecureRandom.hex(16)
    
              expect(response.body).to match("bad_request")
    
          context "when redirect uri is missing" do
            context "when only one redirect URL is pre-registered" do
    
              it "should return a form page" do
    
                # Note this intentionally behavior diverts from OIDC spec http://openid.net/specs/openid-connect-core-1_0.html#AuthRequest
                # When client has only one redirect uri registered, only that redirect uri can be used. Hence,
                # we should implicitly assume the client wants to use that registered URI.
                # See https://github.com/nov/rack-oauth2/blob/master/lib/rack/oauth2/server/authorize.rb#L63
                post :new, client_id: client.client_id, response_type: "id_token",
                     scope: "openid", nonce: SecureRandom.hex(16), state: SecureRandom.hex(16)
                expect(response.body).to match("Diaspora Test Client")
              end
            end
    
          context "when multiple redirect URLs are pre-registered" do
            it "should return an invalid request error" do
              post :new, client_id: client_with_multiple_redirects.client_id, response_type: "id_token",
    
    Augier's avatar
    Augier a validé
                   scope: "openid", nonce: SecureRandom.hex(16), state: SecureRandom.hex(16)
    
              expect(response.body).to match("bad_request")
    
          context "when redirect URI does not match pre-registered URIs" do
            it "should return an invalid request error" do
              post :new, client_id: client.client_id, redirect_uri: "http://localhost:2000/",
                   response_type: "id_token", scope: "openid", nonce: SecureRandom.hex(16)
              expect(response.body).to match("bad_request")
            end
    
          context "when an unsupported scope is passed in" do
            it "should return an invalid scope error" do
              post :new, client_id: client.client_id, redirect_uri: "http://localhost:3000/", response_type: "id_token",
                   scope: "random", nonce: SecureRandom.hex(16), state: SecureRandom.hex(16)
              expect(response.body).to match("error=invalid_scope")
            end
    
          context "when nonce is missing" do
            it "should return an invalid request error" do
              post :new, client_id: client.client_id, redirect_uri: "http://localhost:3000/",
                   response_type: "id_token", scope: "openid", state: SecureRandom.hex(16)
              expect(response.location).to match("error=invalid_request")
            end
    
        context "when already authorized" do
    
          let!(:auth) {
            Api::OpenidConnect::Authorization.find_or_create_by(o_auth_application: client, user: alice,
                                                                            redirect_uri: "http://localhost:3000/")
          }
    
    
          context "when valid parameters are passed" do
            before do
              get :new, client_id: client.client_id, redirect_uri: "http://localhost:3000/", response_type: "id_token",
                  scope: "openid", nonce: 413_093_098_3, state: 413_093_098_3
            end
    
            it "should return the id token in a fragment" do
              expect(response.location).to have_content("id_token=")
              encoded_id_token = response.location[/(?<=id_token=)[^&]+/]
    
    augier's avatar
    augier a validé
              decoded_token = OpenIDConnect::ResponseObject::IdToken.decode encoded_id_token,
    
    theworldbright's avatar
    theworldbright a validé
                                                                            Api::OpenidConnect::IdTokenConfig.public_key
    
              expect(decoded_token.nonce).to eq("4130930983")
    
    theworldbright's avatar
    theworldbright a validé
              expect(decoded_token.exp).to be > Time.zone.now.utc.to_i
    
            end
    
            it "should return the passed in state" do
              expect(response.location).to have_content("state=4130930983")
            end
    
          end
        end
      end
    
      describe "#create" do
    
        context "when id_token token" do
    
            get :new, client_id: client.client_id, redirect_uri: "http://localhost:3000/", response_type: "id_token token",
                scope: "openid", nonce: 418_093_098_3, state: 418_093_098_3
    
          context "when authorization is approved" do
            before do
              post :create, approve: "true"
            end
    
            it "should return the id token in a fragment" do
              encoded_id_token = response.location[/(?<=id_token=)[^&]+/]
    
    augier's avatar
    augier a validé
              decoded_token = OpenIDConnect::ResponseObject::IdToken.decode encoded_id_token,
    
    theworldbright's avatar
    theworldbright a validé
                                                                            Api::OpenidConnect::IdTokenConfig.public_key
    
              expect(decoded_token.nonce).to eq("4180930983")
    
    theworldbright's avatar
    theworldbright a validé
              expect(decoded_token.exp).to be > Time.zone.now.utc.to_i
    
            it "should return a valid access token in a fragment" do
              encoded_id_token = response.location[/(?<=id_token=)[^&]+/]
    
    augier's avatar
    augier a validé
              decoded_token = OpenIDConnect::ResponseObject::IdToken.decode encoded_id_token,
    
    theworldbright's avatar
    theworldbright a validé
                                                                            Api::OpenidConnect::IdTokenConfig.public_key
    
              access_token = response.location[/(?<=access_token=)[^&]+/]
              access_token_check_num = UrlSafeBase64.encode64(OpenSSL::Digest::SHA256.digest(access_token)[0, 128 / 8])
              expect(decoded_token.at_hash).to eq(access_token_check_num)
            end
    
        context "when id_token" do
    
            get :new, client_id: client.client_id, redirect_uri: "http://localhost:3000/", response_type: "id_token",
                scope: "openid", nonce: 418_093_098_3, state: 418_093_098_3
    
          context "when authorization is approved" do
            before do
              post :create, approve: "true"
            end
    
            it "should return the id token in a fragment" do
              expect(response.location).to have_content("id_token=")
              encoded_id_token = response.location[/(?<=id_token=)[^&]+/]
    
    augier's avatar
    augier a validé
              decoded_token = OpenIDConnect::ResponseObject::IdToken.decode encoded_id_token,
    
    theworldbright's avatar
    theworldbright a validé
                                                                            Api::OpenidConnect::IdTokenConfig.public_key
    
              expect(decoded_token.nonce).to eq("4180930983")
    
    theworldbright's avatar
    theworldbright a validé
              expect(decoded_token.exp).to be > Time.zone.now.utc.to_i
    
            end
    
            it "should return the passed in state" do
              expect(response.location).to have_content("state=4180930983")
            end
    
          context "when authorization is denied" do
            before do
              post :create, approve: "false"
            end
    
            it "should return an error in the fragment" do
              expect(response.location).to have_content("error=")
            end
    
            it "should NOT contain a id token in the fragment" do
              expect(response.location).to_not have_content("id_token=")
            end
    
    
        context "when code" do
          before do
            get :new, client_id: client.client_id, redirect_uri: "http://localhost:3000/", response_type: "code",
                scope: "openid", nonce: 418_093_098_3, state: 418_093_098_3
          end
    
          context "when authorization is approved" do
            before do
              post :create, approve: "true"
            end
    
            it "should return the code" do
              expect(response.location).to have_content("code")
            end
    
            it "should return the passed in state" do
              expect(response.location).to have_content("state=4180930983")
            end
          end
    
          context "when authorization is denied" do
            before do
              post :create, approve: "false"
            end
    
            it "should return an error" do
              expect(response.location).to have_content("error")
            end
    
            it "should NOT contain code" do
              expect(response.location).to_not have_content("code")
            end
          end
        end