summaryrefslogtreecommitdiff
path: root/tests/helpers/bonafide_helper.rb
blob: 5b8862282debea96e36821988792093451212f90 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
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
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
#
# helper for the communication with the provider API for creating, authenticating, and deleting accounts.
#

class LeapTest

  def assert_tmp_user
    user = assert_create_user
    assert_authenticate_user(user)
    yield user if block_given?
    assert_delete_user(user)
  rescue StandardError, MiniTest::Assertion => exc
    begin
      assert_delete_user(user)
    rescue
    end
    raise exc
  end

  #
  # attempts to create a user account via the API,
  # returning the user object if successful.
  #
  def assert_create_user(username=nil, auth=nil)
    user = SRP::User.new(username)
    url = api_url("/users.json")
    params = user.to_params
    if auth
      options = api_options(:auth => auth)
    else
      options = api_options
      if property('webapp.invite_required')
        @invite_code = generate_invite_code
        params['user[invite_code]'] = @invite_code
      end
    end

    assert_post(url, params, options) do |body|
      assert response = JSON.parse(body), 'response should be JSON'
      assert response['ok'], "Creating a user should be successful, got #{response.inspect} instead."
      user.ok = true
      user.id = response['id']
    end
    return user
  end

  # TODO: use the api for this instead.
  def generate_invite_code
    `cd /srv/leap/webapp/ && sudo -u leap-webapp RAILS_ENV=production bundle exec rake generate_invites[1]`.gsub(/\n/, "")
  end

  #
  # attempts to authenticate user. if successful,
  # user object is updated with id and session token.
  #
  def assert_authenticate_user(user)
    url = api_url("/sessions.json")
    session = SRP::Session.new(user)
    params = {'login' => user.username, 'A' => session.aa}
    assert_post(url, params, api_options) do |body, response|
      cookie = response['Set-Cookie'].split(';').first
      assert(response = JSON.parse(body), 'response should be JSON')
      assert(session.bb = response["B"], 'response should include "B"')
      url = api_url("/sessions/login.json")
      params = {'client_auth' => session.m, 'A' => session.aa}
      assert_put(url, params, api_options('Cookie' => cookie)) do |body|
        assert(response = JSON.parse(body), 'response should be JSON')
        assert(response['M2'], 'response should include M2')
        user.session_token = response['token']
        user.id = response['id']
        assert(user.session_token, 'response should include token')
        assert(user.id, 'response should include user id')
      end
    end
  end

  #
  # attempts to destroy a user account via the API.
  #
  def assert_delete_user(user)
    if user.is_a? String
      assert_delete_user_by_login(user)
    elsif user.is_a? SRP::User
      assert_delete_srp_user(user)
    end
  end

  #
  # returns true if the identity exists, uses monitor token auth
  #
  def identity_exists?(address)
    url = api_url("/identities/#{URI.encode(address)}.json")
    options = {:ok_codes => [200, 404]}.merge(
      api_options(:auth => :monitor)
    )
    assert_get(url, nil, options) do |body, response|
      return response.code == "200"
    end
  end

  def upload_public_key(user_id, public_key)
    url = api_url("/users/#{user_id}.json")
    params = {"user[public_key]" => public_key}
    assert_put(url, params, api_options(:auth => :monitor))
  end

  #
  # return user document as a Hash. uses monitor token auth
  #
  def find_user_by_id(user_id)
    url = api_url("/users/#{user_id}.json")
    assert_get(url, nil, api_options(:auth => :monitor)) do |body|
      return JSON.parse(body)
    end
  end

  #
  # return user document as a Hash. uses monitor token auth
  # NOTE: this relies on deprecated behavior of the API
  # and will not work when multi-domain support is added.
  #
  def find_user_by_login(login)
    url = api_url("/users/0.json?login=#{login}")
    options = {:ok_codes => [200, 404]}.merge(
      api_options(:auth => :monitor)
    )
    assert_get(url, nil, options) do |body, response|
      if response.code == "200"
        return JSON.parse(body)
      else
        return nil
      end
    end
  end

  private

  def api_url(path)
    unless path =~ /^\//
      path = '/' + path
    end
    if property('testing.api_uri')
      return property('testing.api_uri') + path
    elsif property('api')
      api = property('api')
      return "https://%{domain}:%{port}/%{version}#{path}" % {
        :domain   => api['domain'],
        :port     => api['port'],
        :version  => api['version'] || 1
      }
    else
      fail 'This node needs to have either testing.api_url or api.{domain,port} configured.'
    end
  end

  #
  # produces an options hash used for api http requests.
  #
  # argument options hash gets added to "headers"
  # of the http request.
  #
  # special :auth key in argument will expand to
  # add api_token_auth header.
  #
  # if you want to try manually:
  #
  #   export API_URI=`grep api_uri /etc/leap/hiera.yaml | cut -d\" -f2`
  #   export TOKEN=`grep monitor_auth_token /etc/leap/hiera.yaml | awk '{print $2}'`
  #   curl -H "Accept: application/json" -H "Token: $TOKEN" $API_URI
  #
  def api_options(options={})
    # note: must be :headers, not "headers"
    hsh = {
      :headers => {
        "Accept" => "application/json"
      }
    }
    if options[:auth]
      hsh[:headers].merge!(api_token_auth(options.delete(:auth)))
    end
    hsh[:headers].merge!(options)
    return hsh
  end

  #
  # add token authentication to a http request.
  #
  # returns a hash suitable for adding to the 'headers' option
  # of an http function.
  #
  def api_token_auth(token)
    if token.is_a?(Symbol) && property('testing')
      if token == :monitor
        token_str = property('testing.monitor_auth_token')
      else
        raise ArgumentError.new 'no such token'
      end
    else
      token_str = token
    end
    {"Authorization" => "Token token=\"#{token_str}\""}
  end

  #
  # not actually used in any test, but useful when
  # writing new tests.
  #
  def assert_delete_user_by_login(login_name)
    user = find_user_by_login(login_name)
    url = api_url("/users/#{user['id']}.json")
    params =  {:identities => 'destroy'}
    delete(url, params, api_options(:auth => :monitor)) do |body, response, error|
      assert error.nil?, "Error deleting user: #{error}"
      assert response.code.to_i == 200, "Unable to delete user: HTTP response from API should have code 200, was #{response.code} #{error} #{body}"
      assert(response = JSON.parse(body), 'Delete response should be JSON')
      assert(response["success"], 'Deleting user should be a success')
    end
  end

  def assert_delete_srp_user(user)
    if user && user.ok && user.id && user.session_token && !user.deleted
      url = api_url("users/#{user.id}.json")
      params = {:identities => 'destroy'}
      user.deleted = true
      delete(url, params, api_options(:auth => user.session_token)) do |body, response, error|
        assert error.nil?, "Error deleting user: #{error}"
        assert response.code.to_i == 200, "Unable to delete user: HTTP response from API should have code 200, was #{response.code} #{error} #{body}"
        assert(response = JSON.parse(body), 'Delete response should be JSON')
        assert(response["success"], 'Deleting user should be a success')
      end
    end
  end


end