diff --git a/.gitignore b/.gitignore index 8ae6b57f..2ec26cd8 100644 --- a/.gitignore +++ b/.gitignore @@ -1,5 +1,6 @@ bin/ vendor/ +doc/ .DS_Store .ruby-version coverage diff --git a/.travis.yml b/.travis.yml index 55bda533..f3b95d22 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,3 +9,5 @@ rvm: - 2.2.1 script: ./build_travis.sh + +after_success: ./deploy_documentation.sh diff --git a/Gemfile b/Gemfile index 2bccd000..2e4d8ee8 100644 --- a/Gemfile +++ b/Gemfile @@ -7,4 +7,5 @@ group :development do gem 'terminal-notifier-guard', require: false gem 'coveralls', require: false gem 'rubocop', require: false + gem 'yard', require: false end diff --git a/README.md b/README.md index 01909b1d..9dca54c8 100644 --- a/README.md +++ b/README.md @@ -19,35 +19,33 @@ gem 'auth0' ## Basic usage -Using [APIv1](https://auth0.com/docs/api) +Using [APIv2](https://auth0.com/docs/api/v2) ```ruby require "auth0" auth0 = Auth0Client.new( - :client_id => "YOUR CLIENT ID", - :client_secret => "YOUR CLIENT SECRET", + :token => "YOUR JWT HERE", :domain => ".auth0.com" ) puts auth0.get_users ``` -Using [APIv2](https://auth0.com/docs/apiv2) +Using [APIv1](https://auth0.com/docs/api/v1) ```ruby require "auth0" auth0 = Auth0Client.new( - :api_version => 2, - :token => "YOUR JWT HERE", + :client_id => "YOUR CLIENT ID", + :client_secret => "YOUR CLIENT SECRET", :domain => ".auth0.com" ) puts auth0.get_users ``` - ## What is Auth0? Auth0 helps you to: diff --git a/Rakefile b/Rakefile index fa46c1ec..a7d36346 100644 --- a/Rakefile +++ b/Rakefile @@ -3,10 +3,33 @@ require 'bundler/gem_tasks' begin require 'rubocop/rake_task' - RuboCop::RakeTask.new require 'rspec/core/rake_task' + desc 'Run Rubocop' + RuboCop::RakeTask.new(:rubocop) + + require 'yard' + DOC_FILES = ['lib/auth0/api/v2/*.rb'] + + desc 'Build Documentation' + YARD::Rake::YardocTask.new(:documentation) do |t| + t.files = DOC_FILES + end + + desc 'Publish SDK documentation' + task :publish do + sh 'rake documentation' + sh 'cp -R doc /tmp/ruby-auth0-doc' + sh 'git checkout gh-pages' + sh 'cp -R /tmp/ruby-auth0-doc/* .' + sh 'rm -rf /tmp/ruby-auth0-doc' + sh 'git add .' + sh 'git commit -am "Rebuild documentation"' + sh 'git push origin gh-pages' + sh 'git checkout master' + end + desc 'Run Integration Tests' RSpec::Core::RakeTask.new(:integration) do |t| t.pattern = FileList["spec/integration/**/*#{ENV['PATTERN']}*_spec.rb"] diff --git a/auth0.gemspec b/auth0.gemspec index a9892045..b07f999f 100644 --- a/auth0.gemspec +++ b/auth0.gemspec @@ -18,7 +18,7 @@ Gem::Specification.new do |s| s.executables = `git ls-files -- bin/*`.split("\n").map { |f| File.basename(f) } s.require_paths = ['lib'] - s.add_runtime_dependency 'httparty', '~> 0.13' + s.add_runtime_dependency 'httmultiparty', '~> 0.3.16' s.add_development_dependency 'rake', '~> 10.4' s.add_development_dependency 'fuubar', '~> 2.0' diff --git a/deploy_documentation.sh b/deploy_documentation.sh new file mode 100755 index 00000000..1fab3c9e --- /dev/null +++ b/deploy_documentation.sh @@ -0,0 +1,29 @@ +#!/bin/bash +# exit with nonzero exit code if anything fails +set -e + +# clear and re-create the out directory +rm -rf doc || exit 0; +mkdir doc; + +# build documentation +bundle exec rake documentation + +# go to the out directory and create a *new* Git repo +cd doc +git init + +# inside this git repo we'll pretend to be a new user +git config user.name "Travis CI" +git config user.email "build-documentation@auth0.com" + +# The first and only commit to this new Git repo contains all the +# files present with the commit message "Deploy to GitHub Pages". +git add . +git commit -m "Deploy to GitHub Pages" + +# Force push from the current repo's master branch to the remote +# repo's gh-pages branch. (All previous history on the gh-pages branch +# will be lost, since we are overwriting it.) We redirect any output to +# /dev/null to hide any sensitive credential data that might otherwise be exposed. +git push --force --quiet "https://${GH_TOKEN}@${GH_REF}" master:gh-pages > /dev/null 2>&1 diff --git a/lib/auth0/api/v2.rb b/lib/auth0/api/v2.rb index c7e6049c..67833ea0 100644 --- a/lib/auth0/api/v2.rb +++ b/lib/auth0/api/v2.rb @@ -1,20 +1,28 @@ -require 'auth0/api/v2/clients' -require 'auth0/api/v2/users' require 'auth0/api/v2/blacklists' +require 'auth0/api/v2/clients' +require 'auth0/api/v2/connections' +require 'auth0/api/v2/emails' require 'auth0/api/v2/jobs' +require 'auth0/api/v2/rules' require 'auth0/api/v2/stats' -require 'auth0/api/v2/connections' +require 'auth0/api/v2/users' +require 'auth0/api/v2/tenants' +require 'auth0/api/v2/tickets' module Auth0 module Api # https://auth0.com/docs/apiv2 module V2 - include Auth0::Api::V2::Clients - include Auth0::Api::V2::Users include Auth0::Api::V2::Blacklists + include Auth0::Api::V2::Clients + include Auth0::Api::V2::Connections + include Auth0::Api::V2::Emails include Auth0::Api::V2::Jobs + include Auth0::Api::V2::Rules include Auth0::Api::V2::Stats - include Auth0::Api::V2::Connections + include Auth0::Api::V2::Users + include Auth0::Api::V2::Tenants + include Auth0::Api::V2::Tickets end end end diff --git a/lib/auth0/api/v2/blacklists.rb b/lib/auth0/api/v2/blacklists.rb index 6f68041d..32ef51c7 100644 --- a/lib/auth0/api/v2/blacklists.rb +++ b/lib/auth0/api/v2/blacklists.rb @@ -1,22 +1,43 @@ module Auth0 module Api module V2 - # https://auth0.com/docs/apiv2#!/blacklists + # Methods to use the blacklist endpoints module Blacklists - # https://auth0.com/docs/apiv2#!/blacklists/get_tokens - def blacklisted_tokens - path = '/api/v2/blacklists/tokens' - get(path) + attr_reader :blacklists_path + + # Retrieves the jti and aud of all tokens in the blacklist. + # @see https://auth0.com/docs/api/v2#!/Blacklists/get_tokens + # @param aud [string] The JWT's aud claim. The client_id of the client for which it was issued + # + # @return [json] Returns the blacklisted tokens + # + def blacklisted_tokens(aud = nil) + request_params = { + aud: aud + } + get(blacklists_path, request_params) end - # https://auth0.com/docs/apiv2#!/blacklists/post_tokens + # Adds the token identified by the jti to a blacklist for the tenant. + # @see https://auth0.com/docs/api/v2#!/blacklists/post_tokens + # @param jti [string] The jti of the JWT to blacklist + # @param aud [string] The JWT's aud claim. The client_id of the client for which it was issued + # @return [json] Returns the blacklisted token + # def add_token_to_blacklist(jti, aud = nil) + fail Auth0::MissingParameter, 'Must specify a valid JTI' if jti.to_s.empty? request_params = { jti: jti, aud: aud } - path = '/api/v2/blacklists/tokens' - post(path, request_params) + post(blacklists_path, request_params) + end + + private + + # Blacklists API path + def blacklists_path + @blacklists_path ||= '/api/v2/blacklists/tokens' end end end diff --git a/lib/auth0/api/v2/clients.rb b/lib/auth0/api/v2/clients.rb index a66ca086..e2a54b68 100644 --- a/lib/auth0/api/v2/clients.rb +++ b/lib/auth0/api/v2/clients.rb @@ -1,40 +1,81 @@ module Auth0 module Api module V2 - # https://auth0.com/docs/apiv2#!/clients + # Methods to use the client endpoints module Clients - # https://auth0.com/docs/apiv2#!/clients/get_clients - def clients(options = {}) - path = '/api/v2/clients' - get(path, options) + attr_reader :clients_path + + # Retrieves a list of all client applications. Accepts a list of fields to include or exclude. + # @see https://auth0.com/docs/api/v2#!/clients/get_clients + # @param fields [string] A comma separated list of fields to include or exclude from the result. + # @param include_fields [boolean] if the fields specified are to be included in the result, false otherwise + # + # @return [json] Returns the clients applications. + def clients(fields: nil, include_fields: nil) + include_fields = true if !fields.nil? && include_fields.nil? + request_params = { + fields: fields, + include_fields: include_fields + } + get(clients_path, request_params) end alias_method :get_clients, :clients - # https://auth0.com/docs/apiv2#!/clients/post_clients + # Creates a new client application. + # @see https://auth0.com/docs/api/v2#!/clients/post_clients + # @param name [string] The name of the client. Must contain at least one character. Does not allow '<' or '>' + # @param options [hash] The Hash options used to define the client's properties. + # @return [json] Returns the created client application. def create_client(name, options = {}) + fail Auth0::MissingParameter, 'Must specify a valid client name' if name.to_s.empty? request_params = Hash[options.map { |(k, v)| [k.to_sym, v] }] request_params[:name] = name - path = '/api/v2/clients' - post(path, request_params) + post(clients_path, request_params) end - # https://auth0.com/docs/apiv2#!/clients/get_clients_by_id - def client(client_id, options = {}) - path = "/api/v2/clients/#{client_id}" - get(path, options) + # Retrieves a client by its id. + # @see https://auth0.com/docs/api/v2#!/Clients/get_clients_by_id + # @param client_id [string] The id of the client to retrieve + # @param fields [string] A comma separated list of fields to include or exclude from the result. + # @param include_fields [boolean] If the fields specified are to be included in the result, false otherwise + # @return [json] Returns the requested client application. + def client(client_id, fields: nil, include_fields: nil) + fail Auth0::MissingClientId, 'Must specify a client id' if client_id.to_s.empty? + include_fields = true if !fields.nil? && include_fields.nil? + request_params = { + fields: fields, + include_fields: include_fields + } + path = "#{clients_path}/#{client_id}" + get(path, request_params) end - # https://auth0.com/docs/apiv2#!/clients/delete_clients_by_id + # Deletes a client and all its related assets (like rules, connections, etc) given its id. + # @see https://auth0.com/docs/api/v2#!/Clients/delete_clients_by_id + # @param client_id [string] The id of the client to delete def delete_client(client_id) - path = "/api/v2/clients/#{client_id}" + fail Auth0::MissingClientId, 'Must specify a client id' if client_id.to_s.empty? + path = "#{clients_path}/#{client_id}" delete(path) end - # https://auth0.com/docs/apiv2#!/clients/patch_clients_by_id + # Updates a client. + # @see https://auth0.com/docs/api/v2#!/Clients/patch_clients_by_id + # @param client_id [string] The id of the client to update + # @param options [hash] The Hash options used to define the client's properties. def patch_client(client_id, options) - path = "/api/v2/clients/#{client_id}" + fail Auth0::MissingClientId, 'Must specify a client id' if client_id.to_s.empty? + fail Auth0::MissingParameter, 'Must specify a valid body' if options.to_s.empty? + path = "#{clients_path}/#{client_id}" patch(path, options) end + + private + + # Clients API path + def clients_path + @clients_path ||= '/api/v2/clients' + end end end end diff --git a/lib/auth0/api/v2/connections.rb b/lib/auth0/api/v2/connections.rb index cecc7d4c..ebd4000c 100644 --- a/lib/auth0/api/v2/connections.rb +++ b/lib/auth0/api/v2/connections.rb @@ -1,27 +1,49 @@ module Auth0 module Api module V2 - # https://auth0.com/docs/api/v2#!/Connections + # Methods to use the connections endpoints module Connections + attr_reader :connections_path + + # Retrieves every connection matching the specified strategy. All connections are retrieved if no strategy is + # being specified. Accepts a list of fields to include or exclude in the resulting list of connection objects. + # @see https://auth0.com/docs/api/v2#!/Connections/get_connections + # @param strategy [string] Provide a type of strategy to only retrieve connections with that strategy + # @param fields [string] A comma separated list of fields to include or exclude from the result. + # @param include_fields [boolean] if the fields specified are to be included in the result, false otherwise. + # + # @return [json] Returns the existing connections matching the strategy. def connections(strategy: nil, fields: nil, include_fields: true) request_params = { strategy: strategy, fields: fields, include_fields: include_fields } - path = '/api/v2/connections' - get(path, request_params) + get(connections_path, request_params) end alias_method :get_connections, :connections + # Creates a new connection according to the JSON object received in body. + # @see https://auth0.com/docs/api/v2#!/Connections/post_connections + # @param body [hash] The Hash options used to define the conecctions's properties. + # + # @return [json] Returns the created connection. def create_connection(body) - path = '/api/v2/connections' + fail Auth0::InvalidParameter, 'Must specify a body to create a connection' if body.to_s.empty? request_params = body - post(path, request_params) + post(connections_path, request_params) end + # Retrieves a connection by its id. + # @see https://auth0.com/docs/api/v2#!/Connections/get_connections_by_id + # @param connection_id [string] The id of the connection to retrieve + # @param fields [string] A comma separated list of fields to include or exclude from the result. + # @param include_fields [boolean] if the fields specified are to be included in the result, false otherwise + # + # @return [json] Returns the matching connection def connection(connection_id, fields: nil, include_fields: true) - path = "/api/v2/connections/#{connection_id}" + fail Auth0::InvalidParameter, 'Must supply a valid connection id' if connection_id.to_s.empty? + path = "#{connections_path}/#{connection_id}" request_params = { fields: fields, include_fields: include_fields @@ -29,17 +51,47 @@ def connection(connection_id, fields: nil, include_fields: true) get(path, request_params) end + # Deletes a connection and all its users. + # @see https://auth0.com/docs/api/v2#!/Connections/delete_connections_by_id + # @param connection_id [string] The id of the connection to delete def delete_connection(connection_id) - fail Auth0::MissingConnectionId, 'you must specify a connection id' if connection_id.to_s.empty? - path = "/api/v2/connections/#{connection_id}" + fail Auth0::InvalidParameter, 'Must supply a valid connection id' if connection_id.to_s.empty? + path = "#{connections_path}/#{connection_id}" + delete(path) + end + + # Deletes a specified connection user by its email (currently only database connections are supported and you + # cannot delete all users from specific connection). + # @see https://auth0.com/docs/api/v2#!/Connections/delete_users + # @param connection_id [string] The id of the connection + # @param user_email [string] The email of the user to delete + # + # @return [json] Returns the updated connection. + def delete_connection_user(connection_id, user_email) + fail Auth0::InvalidParameter, 'Must supply a valid connection id' if connection_id.to_s.empty? + fail Auth0::InvalidParameter, 'Must supply a valid user email' if user_email.to_s.empty? + path = "#{connections_path}/#{connection_id}/users?email=#{user_email}" delete(path) end + # Updates a connection. Updates the fields specified in the body parameter. + # @see https://auth0.com/docs/api/v2#!/Connections/patch_connections_by_id + # @param connection_id [string] The id of the connection to delete + # @param body [hash] The Hash options used to update the conecctions's properties. + # + # @return [json] Returns the updated connection. def update_connection(connection_id, body) - fail Auth0::MissingConnectionId, 'you must specify a connection id' if connection_id.to_s.empty? - path = "/api/v2/connections/#{connection_id}" + fail Auth0::InvalidParameter, 'Must supply a valid connection id' if connection_id.to_s.empty? + path = "#{connections_path}/#{connection_id}" patch(path, body) end + + private + + # Connections API path + def connections_path + @connections_path ||= '/api/v2/connections' + end end end end diff --git a/lib/auth0/api/v2/emails.rb b/lib/auth0/api/v2/emails.rb new file mode 100644 index 00000000..8d6c8c6f --- /dev/null +++ b/lib/auth0/api/v2/emails.rb @@ -0,0 +1,58 @@ +module Auth0 + module Api + module V2 + # Methods to use the connections endpoints + module Emails + attr_reader :email_path + + # Get all the email providers. + # @see https://auth0.com/docs/api/v2#!/Emails/get_provider + # @param fields [string] A comma separated list of fields to include or exclude from the result. + # @param include_fields [boolean] if the fields specified are to be included in the result, false otherwise. + # + # @return [json] Returns the existing email providers. + def get_provider(fields: nil, include_fields: nil) + request_params = { + fields: fields, + include_fields: include_fields + } + get(email_path, request_params) + end + + # Configure a new email provider. + # @see https://auth0.com/docs/api/v2#!/Emails/post_provider + # @param body [hash] The Hash options used to spcify the email provider's properties. + # + # @return [json] Returns the created email provider. + def configure_provider(body) + fail Auth0::InvalidParameter, 'Must supply a valid body to create an email provider' if body.to_s.empty? + post(email_path, body) + end + + # Deletes the configured email provider. + # @see https://auth0.com/docs/api/v2#!/Emails/delete_provider + # + # @return [json] Returns the created email provider. + def delete_provider + delete(email_path) + end + + # Updates the configured email provider. + # @see https://auth0.com/docs/api/v2#!/Emails/patch_provider + # @param body [hash] The Hash options used to spcify the email provider's properties. + # + # @return [json] Returns the updated email provider. + def update_provider(body) + fail Auth0::InvalidParameter, 'Must supply a valid body to update an email provider' if body.to_s.empty? + patch(email_path, body) + end + + private + + def email_path + @email_path ||= '/api/v2/emails/provider' + end + end + end + end +end diff --git a/lib/auth0/api/v2/jobs.rb b/lib/auth0/api/v2/jobs.rb index ad52b679..d00e592a 100644 --- a/lib/auth0/api/v2/jobs.rb +++ b/lib/auth0/api/v2/jobs.rb @@ -1,20 +1,55 @@ module Auth0 module Api module V2 - # https://auth0.com/docs/apiv2#!/jobs + # Methods to use the jobs endpoints module Jobs - # https://auth0.com/docs/apiv2#!/jobs/get_jobs_by_job_id + attr_reader :jobs_path + + # Retrieves a job. Useful to check its status. + # @see https://auth0.com/docs/api/v2#!/Jobs/get_jobs_by_job_id + # @param job_id [string] The id of the job + # + # @return [json] the job status and properties def get_job(job_id) - path = "/api/v2/jobs/#{job_id}" + fail Auth0::InvalidParameter, 'Must specify a job id' if job_id.to_s.empty? + path = "#{jobs_path}/#{job_id}" get(path) end - # HTTParty doesn't support multipart upload, will move this - # functionality to a separate PR - # https://auth0.com/docs/apiv2#!/jobs/post_users_imports - # rubocop:disable UnusedMethodArgument - def create_job(users_file, connection_name) - fail NotImplementedError + # Imports users to a connection from a file using a long running job. + # Important: The documentation for the file format is at https://docs.auth0.com/bulk-import. + # @see https://auth0.com/docs/api/v2#!/Jobs/post_users_imports + # @param users_file [file] A file containing the users to import + # @param connection_id [string] The connection id of the connection to which users will be inserted + # + # @return [json] the job status and properties + def import_users(users_file, connection_id) + fail Auth0::InvalidParameter, 'Must specify a valid file' if users_file.to_s.empty? + fail Auth0::InvalidParameter, 'Must specify a connection_id' if connection_id.to_s.empty? + request_params = { + users: users_file, + connection_id: connection_id + } + path = "#{jobs_path}/users-imports" + post_file(path, request_params) + end + + # Send an email to the specified user that asks them to click a link to verify their email address. + # @see https://auth0.com/docs/api/v2#!/Jobs/post_verification_email + # @param user_id [string] The user_id of the user to whom the email will be sent + # + # @return [json] the job status and properties + def send_verification_email(user_id) + fail Auth0::InvalidParameter, 'Must specify a user id' if user_id.to_s.empty? + path = "#{jobs_path}/verification-email" + post(path, user_id) + end + + private + + # Jobs API path + def jobs_path + @jobs_path ||= '/api/v2/jobs' end end end diff --git a/lib/auth0/api/v2/rules.rb b/lib/auth0/api/v2/rules.rb new file mode 100644 index 00000000..4f9d377e --- /dev/null +++ b/lib/auth0/api/v2/rules.rb @@ -0,0 +1,104 @@ +module Auth0 + module Api + module V2 + # Methods to use the rules endpoints + module Rules + attr_reader :rules_path + + # Retrieves a list of all rules. Accepts a list of fields to include or exclude. + # The enabled parameter can be specified to get enabled or disabled rules. + # The rule's stage of executing could be set to the following values login_success, + # login_failure or pre_authorize + # @see https://auth0.com/docs/api/v2#!/Rules/get_rules + # @param enabled [boolean] If provided retrieves rules that match the value, otherwise all rules are retrieved + # @param fields [string] A comma separated list of fields to include or exclude from the result. + # @param include_fields [boolean] If the fields specified are to be included in the result, false otherwise + # @param stage [string] Retrieves rules that match the execution stage (defaults to login_success) + # + # @return [json] Returns the existing rules. + def rules(enabled: nil, fields: nil, include_fields: nil, stage: nil) + request_params = { + enabled: enabled, + fields: fields, + include_fields: include_fields, + stage: stage + } + get(rules_path, request_params) + end + + alias_method :get_rules, :rules + + # Retrieves a rule by its ID. Accepts a list of fields to include or exclude in the result. + # @see https://auth0.com/docs/api/v2#!/Rules/get_rules_by_id + # @param rule_id [string] The id of the rule to retrieve + # @param fields [string] A comma separated list of fields to include or exclude from the result. + # @param include_fields [boolean] If the fields specified are to be included in the result, false otherwise + # + # @return [json] Returns the rule. + def rule(rule_id, fields: nil, include_fields: nil) + fail Auth0::InvalidParameter, 'Must supply a valid rule id' if rule_id.to_s.empty? + path = "#{rules_path}/#{rule_id}" + request_params = { + fields: fields, + include_fields: include_fields + } + get(path, request_params) + end + + alias_method :get_rule, :rule + + # Creates a new rule according to the JSON object received in body. + # @see https://auth0.com/docs/api/v2#!/Rules/post_rules + # @param name [string] The name of the rule. Can only contain alphanumeric characters, spaces and '-'. + # @param script [string] A script that contains the rule's code + # @param order [integer] The rule's order in relation to other rules. A rule with a lower order than another rule + # executes first. If no order is provided it will automatically be one greater than the current maximum + # @param enabled [string] true if the rule is enabled, false otherwise + # @param stage [string] The rule's execution stage 'login_success' or 'login_failure' or 'pre_authorize' or + # 'user_registration' or 'user_blocked' + # + # @return [json] Returns the rule. + def create_rule(name, script, order = nil, enabled = true, stage = 'login_success') + fail Auth0::InvalidParameter, 'Must supply a valid name' if name.to_s.empty? + fail Auth0::InvalidParameter, 'Must supply a valid script' if script.to_s.empty? + request_params = { + name: name, + enabled: enabled, + script: script, + order: order, + stage: stage + } + post(rules_path, request_params) + end + + # Updates a rule. + # @see https://auth0.com/docs/api/v2#!/Rules/patch_rules_by_id + # @param rule_id [string] The id of the rule to retrieve + # @param fields_to_update [hash] The Hash fields_to_update used to define the rule's properties. + # @return [json] Returns the updated rule. + def update_rule(rule_id, fields_to_update = {}) + fail Auth0::InvalidParameter, 'Must supply a valid rule id' if rule_id.to_s.empty? + + path = "#{rules_path}/#{rule_id}" + patch(path, fields_to_update) + end + + # Deletes a rule. + # @see https://auth0.com/docs/api/v2#!/Rules/delete_rules_by_id + # @param rule_id [string] The id of the rule to retrieve + def delete_rule(rule_id) + fail Auth0::InvalidParameter, 'Must supply a valid rule id' if rule_id.to_s.empty? + path = "#{rules_path}/#{rule_id}" + delete(path) + end + + private + + # Rules API path + def rules_path + @rules_path ||= '/api/v2/rules' + end + end + end + end +end diff --git a/lib/auth0/api/v2/stats.rb b/lib/auth0/api/v2/stats.rb index 96c3b33b..ba797d83 100644 --- a/lib/auth0/api/v2/stats.rb +++ b/lib/auth0/api/v2/stats.rb @@ -1,23 +1,40 @@ module Auth0 module Api module V2 - # https://auth0.com/docs/apiv2#!/stats + # Methods to use the stats endpoints module Stats - # https://auth0.com/docs/apiv2#!/stats/get_active_users + attr_reader :stats_path + + # Gets the active users count (logged in during the last 30 days). + # @see https://auth0.com/docs/api/v2#!/Stats/get_active_users + # + # @return [integer] Returns numbers def active_users - path = '/api/v2/stats/active-users' + path = "#{stats_path}/active-users" get(path) end - # https://auth0.com/docs/apiv2#!/stats/get_daily + # Gets the daily stats for a particular period. + # @see https://auth0.com/docs/api/v2#!/Stats/get_daily + # @param from [string] The first day of the period (inclusive) in YYYYMMDD format. + # @param to [string] The last day of the period (inclusive) in YYYYMMDD format. + # + # @return [json] Returns the daily stats. def daily_stats(from, to) - path = '/api/v2/stats/daily' + path = "#{stats_path}/daily" request_params = { from: from, to: to } get(path, request_params) end + + private + + # Stats API path + def stats_path + @stats_path ||= '/api/v2/stats' + end end end end diff --git a/lib/auth0/api/v2/tenants.rb b/lib/auth0/api/v2/tenants.rb new file mode 100644 index 00000000..b2a4a2f6 --- /dev/null +++ b/lib/auth0/api/v2/tenants.rb @@ -0,0 +1,39 @@ +module Auth0 + module Api + module V2 + # Methods to use the Tenants endpoints + module Tenants + attr_reader :tenant_path + + # Gets tenants settings. + # @see https://auth0.com/docs/api/v2#!/Tenants/get_settings + # @param fields [string] A comma separated list of fields to include or exclude from the result. + # @param include_fields [boolean] If the fields specified are to be included in the result, false otherwise + # @return [json] Returns tenants settings. + def get_tenant_settings(fields: nil, include_fields: true) + request_params = { + fields: fields, + include_fields: include_fields + } + get(tenant_path, request_params) + end + + # Updates tenants settings. + # @see https://auth0.com/docs/api/v2#!/Tenants/patch_settings + # @param body [hash] The Hash body used to define the tenants settings's properties. + # @return [json] Returns updated tenants settings. + def update_tenant_settings(body) + fail Auth0::InvalidParameter, 'Must supply a valid body to update tenant settings' if body.to_s.empty? + patch(tenant_path, body) + end + + private + + # Tenants settings API path + def tenant_path + @tenant_path ||= '/api/v2/tenants/settings' + end + end + end + end +end diff --git a/lib/auth0/api/v2/tickets.rb b/lib/auth0/api/v2/tickets.rb new file mode 100644 index 00000000..7c734adf --- /dev/null +++ b/lib/auth0/api/v2/tickets.rb @@ -0,0 +1,58 @@ +module Auth0 + module Api + module V2 + # Methods to use the tickets endpoints + module Tickets + attr_reader :tickets_path + + # Create an email verification ticket + # @see https://auth0.com/docs/api/v2#!/Tickets/post_email_verification + # @param user_id [string] The user_id of for which the ticket is to be created + # @param result_url [string] The user will be redirected to this endpoint once the ticket is used + # @return [json] Returns ticket url + def post_email_verification(user_id, result_url: nil) + if user_id.to_s.empty? + fail Auth0::InvalidParameter, 'Must supply a valid user id to post an email verification' + end + path = "#{tickets_path}/email-verification" + request_params = { + user_id: user_id, + result_url: result_url + } + post(path, request_params) + end + + # Create a password change ticket + # @see https://auth0.com/docs/api/v2#!/Tickets/post_password_change + # @param new_password [string] The password to set for the user once the ticket is used + # @param user_id [string] The user_id of for which the ticket is to be created + # @param result_url [string] The user will be redirected to this endpoint once the ticket is used + # @param connection_id [string] The connection that provides the identity for which the password is to be + # changed. If sending this parameter, the email is also required and the user_id is invalid + # @param email [string] The user's email + # @return [json] Returns ticket url + def post_password_change(new_password, user_id: nil, result_url: nil, connection_id: nil, email: nil) + if new_password.to_s.empty? + fail Auth0::InvalidParameter, 'Must supply a valid new password to post a password-change' + end + path = "#{tickets_path}/password-change" + request_params = { + user_id: user_id, + result_url: result_url, + new_password: new_password, + connection_id: connection_id, + email: email + } + post(path, request_params) + end + + private + + # Tickets API path + def tickets_path + @tickets_path ||= '/api/v2/tickets' + end + end + end + end +end diff --git a/lib/auth0/api/v2/users.rb b/lib/auth0/api/v2/users.rb index 8cb6d048..a894966f 100644 --- a/lib/auth0/api/v2/users.rb +++ b/lib/auth0/api/v2/users.rb @@ -1,9 +1,23 @@ module Auth0 module Api module V2 - # https://auth0.com/docs/apiv2#!/users + # Methods to use the users endpoints module Users - # https://auth0.com/docs/apiv2#!/users/get_users + attr_reader :users_path + + # Retrieves a list of existing users. + # @see https://auth0.com/docs/api/v2#!/Users/get_users + # @param per_page [integer] The amount of entries per page. Default: 50. Max value: 100 + # @param page [integer] The page number. Zero based + # @param include_totals [boolean] true if a query summary must be included in the result + # @param sort [string] The field to use for sorting. 1 == ascending and -1 == descending + # @param connection [string] Connection filter + # @param fields [string] A comma separated list of fields to include or exclude from the result. + # @param include_fields [boolean] if the fields specified are to be included in the result, false otherwise. + # @param q [string] Query in Lucene query string syntax. Only fields in app_metadata, user_metadata or the + # normalized user profile are searchable. + # + # @return [json] The list of existing users. def users(options = {}) request_params = { per_page: options.fetch(:per_page, nil), @@ -12,57 +26,135 @@ def users(options = {}) sort: options.fetch(:sort, nil), connection: options.fetch(:connection, nil), fields: options.fetch(:fields, nil), + include_fields: options.fetch(:include_fields, nil), q: options.fetch(:q, nil) } - request_params[:search_engine] = :v2 if request_params[:q] - - path = '/api/v2/users' - get(path, request_params) + get(users_path, request_params) end alias_method :get_users, :users - # https://auth0.com/docs/apiv2#!/users/post_users + # Creates a new user according to optional parameters received. + # The attribute connection is always mandatory but depending on the type of connection you are using there + # could be others too. For instance, Auth0 DB Connections require email and password. + # @see https://auth0.com/docs/api/v2#!/Users/post_users + # @param name [string] the user name + # @param connection [string] The connection the user belongs to + # + # @return [json] def create_user(name, options = {}) - path = '/api/v2/users' request_params = Hash[options.map { |(k, v)| [k.to_sym, v] }] request_params[:name] = name - post(path, request_params) + post(users_path, request_params) end - # https://auth0.com/docs/apiv2#!/users/delete_users + # Delete all users - USE WITH CAUTION + # @see https://auth0.com/docs/api/v2#!/Users/delete_users def delete_users - path = '/api/v2/users' - delete(path) + delete(users_path) end - # https://auth0.com/docs/apiv2#!/users/get_users_by_id - def user(user_id, fields: nil) - path = "/api/v2/users/#{user_id}" + # Retrieves a user given a user_id + # @see https://auth0.com/docs/api/v2#!/Users/get_users_by_id + # @param user_id [string] The user_id of the user to retrieve + # @param fields [string] A comma separated list of fields to include or exclude from the result. + # @param include_fields [boolean] if the fields specified are to be included in the result, false otherwise. + # + # @return [json] the user with the given user_id if exists + def user(user_id, fields: nil, include_fields: true) + fail Auth0::MissingUserId, 'Must supply a valid user_id' if user_id.to_s.empty? + path = "#{users_path}/#{user_id}" request_params = { - fields: fields + fields: fields, + include_fields: include_fields } get(path, request_params) end - # https://auth0.com/docs/apiv2#!/users/delete_users_by_id + # Deletes a single user given its id + # @see https://auth0.com/docs/api/v2#!/Users/delete_users_by_id + # @param user_id [string] The user_id of the user to delete def delete_user(user_id) - fail Auth0::MissingUserId, 'Must supply a valid user_id' if user_id.nil? || user_id.to_s.empty? - path = "/api/v2/users/#{user_id}" + fail Auth0::MissingUserId, 'Must supply a valid user_id' if user_id.to_s.empty? + path = "#{users_path}/#{user_id}" delete(path) end - # https://auth0.com/docs/apiv2#!/users/patch_users_by_id - def patch_user(user_id, options) - path = "/api/v2/users/#{user_id}" - patch(path, options) + # Updates a user with the object's properties received in the optional parameters. + # These are the attributes that can be updated at the root level: + # blocked, email_verified, email, verify_email, password, phone_number, phone_verified, + # verify_password, user_metadata, app_metadata, username + # Some considerations: + # The properties of the new object will replace the old ones. + # The metadata fields are an exception to this rule (user_metadata and app_metadata). These properties are + # merged instead of being replaced but be careful, the merge only occurs on the first level. + # If you are updating email_verified, phone_verified, username or password you need to specify the connection + # property too. + # If your are updating email or phone_number you need to specify the connection and the client_id properties. + # @see https://auth0.com/docs/api/v2#!/Users/patch_users_by_id + # @param user_id [string] The user_id of the user to update. + # @param body [hash] The optional parametes to update + # + # @return [json] the updated user + def patch_user(user_id, body) + fail Auth0::MissingUserId, 'Must supply a valid user_id' if user_id.to_s.empty? + fail Auth0::InvalidParameter, 'Must supply a valid body' if body.to_s.empty? + path = "#{users_path}/#{user_id}" + patch(path, body) end - # https://auth0.com/docs/apiv2#!/users/delete_multifactor_by_provider + # Delete a user's multifactor provider + # @see https://auth0.com/docs/api/v2#!/Users/delete_multifactor_by_provider + # @param user_id [string] The user_id of the user to delete + # @param provider_name [string] The multifactor provider. Supported values 'duo' or 'google-authenticator' def delete_user_provider(user_id, provider_name) - path = "/api/v2/users/#{user_id}/multifactor/#{provider_name}" + fail Auth0::MissingUserId, 'Must supply a valid user_id' if user_id.to_s.empty? + fail Auth0::InvalidParameter, 'Must supply a valid provider name' if provider_name.to_s.empty? + path = "#{users_path}/#{user_id}/multifactor/#{provider_name}" delete(path) end + + # Links the account specified in the body (secondary account) to the account specified by the id param + # of the URL (primary account). + # 1. With the authenticated primary account's JWT in the Authorization header, which has the + # update:current_user_identities scope. In this case only the link_with param is required in the body, + # containing the JWT obtained upon the secondary account's authentication. + # 2. With an API V2 generated token with update:users scope. In this case you need to send provider and user_id + # in the body. Optionally you can also send the connection_id param which is suitable for identifying a + # particular database connection for the 'auth0' provider. + # @see https://auth0.com/docs/api/v2#!/Users/post_identities + # @param user_id [string] The user_id of the primary identity where you are linking the secondary account to. + # @param body [string] the options to link the account to. + # + # @return [json] the new array of the primary account identities. + def link_user_account(user_id, body) + fail Auth0::MissingUserId, 'Must supply a valid user_id' if user_id.to_s.empty? + fail Auth0::InvalidParameter, 'Must supply a valid body' if body.to_s.empty? + path = "#{users_path}/#{user_id}/identities" + post(path, body) + end + + # Unlink a user account + # @see https://auth0.com/docs/api/v2#!/Users/delete_provider_by_user_id + # @param user_id [string] The user_id of the user identity. + # @param provider [string] The type of identity provider. + # @param secondary_user_id [string] The unique identifier for the user for the identity. + # + # @return [json] the array of the unlinked account identities. + def unlink_users_account(user_id, provider, secondary_user_id) + fail Auth0::MissingUserId, 'Must supply a valid user_id' if user_id.to_s.empty? + fail Auth0::MissingUserId, 'Must supply a valid secondary user_id' if secondary_user_id.to_s.empty? + fail Auth0::InvalidParameter, 'Must supply a valid provider' if provider.to_s.empty? + path = "#{users_path}/#{user_id}/identities/#{provider}/#{secondary_user_id}" + delete(path) + end + + private + + # Users API path + def users_path + @users_path ||= '/api/v2/users' + end end end end diff --git a/lib/auth0/client.rb b/lib/auth0/client.rb index 940bc5de..3155fd25 100644 --- a/lib/auth0/client.rb +++ b/lib/auth0/client.rb @@ -3,7 +3,7 @@ module Auth0 # All Api calls are suposed to return hashes, but delete actions return strings. class Client include Auth0::Mixins - include HTTParty + include HTTMultiParty base_uri 'http://auth0.com' end end diff --git a/lib/auth0/exception.rb b/lib/auth0/exception.rb index 1dc2249b..58e4ac30 100644 --- a/lib/auth0/exception.rb +++ b/lib/auth0/exception.rb @@ -16,10 +16,12 @@ class ServerError < Auth0::Exception; end # exception for incorrect request, you've sent wrong params class BadRequest < Auth0::Exception; end # exception for unset user_id, this might cause removal of - # all users, or other unexpected bahaviour + # all users, or other unexpected behaviour class MissingUserId < Auth0::Exception; end - # exception for an unset connection_id - class MissingConnectionId < Auth0::Exception; end + # exception for unset client_id + class MissingClientId < Auth0::Exception; end + # exception for an unset parameter + class MissingParameter < Auth0::Exception; end # Api v2 access denied class AccessDenied < Auth0::Exception; end # Invalid parameter passed, e.g. empty where ID is required diff --git a/lib/auth0/mixins.rb b/lib/auth0/mixins.rb index bcc92902..a0204244 100644 --- a/lib/auth0/mixins.rb +++ b/lib/auth0/mixins.rb @@ -1,4 +1,4 @@ -require 'httparty' +require 'httmultiparty' require 'uri' require 'auth0/mixins/httparty_proxy' require 'auth0/mixins/initializer' diff --git a/lib/auth0/mixins/httparty_proxy.rb b/lib/auth0/mixins/httparty_proxy.rb index c12461a8..a3beda34 100644 --- a/lib/auth0/mixins/httparty_proxy.rb +++ b/lib/auth0/mixins/httparty_proxy.rb @@ -4,12 +4,14 @@ module Mixins # for now, if you want to feel free to use your own http client module HTTPartyProxy # proxying requests from instance methods to HTTParty class methods - %i(get post put patch delete).each do |method| + %i(get post post_file put patch delete).each do |method| define_method(method) do |path, body = {}| safe_path = URI.escape(path) body = body.delete_if { |_, v| v.nil? } if method == :get result = self.class.send(method, safe_path, query: body) + elsif method == :post_file + result = self.class.send(:post, safe_path, body: body, detect_mime_type: true) else result = self.class.send(method, safe_path, body: body.to_json) end diff --git a/spec/integration/lib/auth0/api/v1/api_users_spec.rb b/spec/integration/lib/auth0/api/v1/api_users_spec.rb index 5ab58b09..ec3a9fb2 100644 --- a/spec/integration/lib/auth0/api/v1/api_users_spec.rb +++ b/spec/integration/lib/auth0/api/v1/api_users_spec.rb @@ -4,16 +4,20 @@ let(:username) { Faker::Internet.user_name } let(:email) { "#{entity_suffix}#{Faker::Internet.safe_email(username)}" } let(:password) { Faker::Internet.password } - let(:connection) { 'Username-Password-Authentication' } - let!(:user) { client.create_user(email, password, connection, 'username' => username, 'email_verified' => false) } + let!(:user) do + client.create_user(email, password, Auth0::Api::AuthenticationEndpoints::UP_AUTH, + 'username' => username, 'email_verified' => false) + end - describe '.users' do - let(:users) { client.users } + skip 'Users examples are skipped' do + describe '.users' do + let(:users) { client.users } - it { expect(users.size).to be > 0 } + it { expect(users.size).to be > 0 } - context '#filters' do - it { expect(client.users("email: #{email}").size).to be 1 } + context '#filters' do + it { expect(client.users("email: #{email}").size).to be 1 } + end end end diff --git a/spec/integration/lib/auth0/api/v2/api_blacklist_spec.rb b/spec/integration/lib/auth0/api/v2/api_blacklist_spec.rb new file mode 100644 index 00000000..0f66bd73 --- /dev/null +++ b/spec/integration/lib/auth0/api/v2/api_blacklist_spec.rb @@ -0,0 +1,14 @@ +require 'spec_helper' +describe Auth0::Api::V2::Blacklists do + let(:client) { Auth0Client.new(v2_creds) } + let(:token) { 'faketoken' } + + describe '.add_token_to_blacklist' do + it { expect(client.add_token_to_blacklist(token)).to be_nil } + end + + describe '.blacklisted_tokens' do + let(:response) { { 'aud' => ENV['GLOBAL_CLIENT_ID'], 'jti' => token } } + it { expect(client.blacklisted_tokens).to include response } + end +end diff --git a/spec/integration/lib/auth0/api/v2/api_clients_spec.rb b/spec/integration/lib/auth0/api/v2/api_clients_spec.rb index c19d4470..473be5ea 100644 --- a/spec/integration/lib/auth0/api/v2/api_clients_spec.rb +++ b/spec/integration/lib/auth0/api/v2/api_clients_spec.rb @@ -6,20 +6,68 @@ it { expect(client.clients).to_not be_empty } - it do - expect(client.create_client(client_name, custom_login_page_on: false)).to( - include('name' => client_name, 'custom_login_page_on' => false)) + describe '.clients' do + let(:clients) { client.clients } + + it { expect(clients.size).to be > 0 } + + context '#filters' do + it do + expect(client.clients(fields: [:name, :callbacks].join(',')).first).to(include('name', 'callbacks')) + end + it do + expect(client.clients(fields: [:callbacks].join(',')).first).to_not(include('name')) + end + it do + expect(client.clients(fields: [:callbacks].join(','), include_fields: false).first).to_not(include('callbacks')) + end + end end - it do - expect( - client.patch_client( - existing_client['client_id'], - custom_login_page_on: false, - sso: true)).to(include('custom_login_page_on' => false, 'sso' => true)) + describe '.client' do + it { expect(client.client(existing_client['client_id'])).to include('client_id' => existing_client['client_id']) } + it { expect { client.client '' }.to raise_error(Auth0::MissingClientId) } + + context '#filters' do + let(:client_include) do + client.client(existing_client['client_id'], fields: [:name, :client_secret, :jwt_configuration].join(',')) + end + let(:client_not_include) do + client.client(existing_client['client_id'], fields: :jwt_configuration, include_fields: false) + end + + it do + expect(client_include).to(include('name', 'client_secret', 'jwt_configuration')) + end + + it do + expect(client_not_include).to(include('name', 'client_secret')) + expect(client_not_include).to_not(include('jwt_configuration')) + end + end end - it { expect { client.delete_client(existing_client['client_id']) }.to_not raise_error } + describe '.create_client' do + it do + expect(client.create_client(client_name, custom_login_page_on: false)).to( + include('name' => client_name, 'custom_login_page_on' => false)) + end + it { expect { client.create_client('', custom_login_page_on: false) }.to raise_error(Auth0::MissingParameter) } + end + + describe '.patch_client' do + it do + expect( + client.patch_client( + existing_client['client_id'], + custom_login_page_on: false, + sso: true)).to(include('custom_login_page_on' => false, 'sso' => true)) + end + it { expect { client.patch_client('', custom_login_page_on: false) }.to raise_error(Auth0::MissingClientId) } + end - it { expect(client.client(existing_client['client_id'])).to include('client_id' => existing_client['client_id']) } + describe '.delete_rule' do + it { expect { client.delete_client(existing_client['client_id']) }.to_not raise_error } + it { expect { client.delete_client '' }.to raise_error(Auth0::MissingClientId) } + end end diff --git a/spec/integration/lib/auth0/api/v2/api_connections_spec.rb b/spec/integration/lib/auth0/api/v2/api_connections_spec.rb index 87519eaf..9a190c98 100644 --- a/spec/integration/lib/auth0/api/v2/api_connections_spec.rb +++ b/spec/integration/lib/auth0/api/v2/api_connections_spec.rb @@ -1,17 +1,17 @@ require 'spec_helper' describe Auth0::Api::V2::Connections do - let(:client) { Auth0Client.new(v2_creds) } + attr_reader :client, :connection, :strategy, :name, :enabled_clients, :options - let(:name) { SecureRandom.uuid[0..25] } - let(:strategy) { 'google-oauth2' } - let(:options) { {} } - let(:enabled_clients) { [] } - - let!(:connection) do - client.create_connection(name: name, - strategy: strategy, - options: options, - enabled_clients: enabled_clients) + before(:all) do + @client = Auth0Client.new(v2_creds) + @name = "#{SecureRandom.uuid[0..25]}#{entity_suffix}" + @strategy = 'google-oauth2' + @options = {} + @enabled_clients = [] + @connection = client.create_connection(name: name, + strategy: strategy, + options: options, + enabled_clients: enabled_clients) end describe '.connections' do @@ -53,11 +53,45 @@ describe '.delete_connection' do it { expect { client.delete_connection connection['id'] }.to_not raise_error } - it { expect { client.delete_connection '' }.to raise_error(Auth0::MissingConnectionId) } end describe '.update_connection' do + let!(:connection_to_update) do + client.create_connection(name: "#{SecureRandom.uuid[0..25]}#{entity_suffix}", + strategy: strategy, + options: options, + enabled_clients: enabled_clients) + end new_name = SecureRandom.uuid[0..25] - it { expect(client.update_connection(connection['id'], 'name' => new_name)).to include('name' => new_name) } + let(:options) { { username: new_name } } + it do + expect(client.update_connection(connection_to_update['id'], 'options' => options)['options']).to include( + 'username' => new_name) + end + end + + describe '.delete_connection_user' do + let(:username) { Faker::Internet.user_name } + let(:email) { "#{entity_suffix}#{Faker::Internet.safe_email(username)}" } + let(:password) { Faker::Internet.password } + let!(:user_to_delete) do + client.create_user(username, email: email, + password: password, + email_verified: false, + connection: Auth0::Api::AuthenticationEndpoints::UP_AUTH, + app_metadata: {}) + end + let(:connection) do + client.connections.find { |connection| connection['name'] == Auth0::Api::AuthenticationEndpoints::UP_AUTH } + end + + it { expect(client.delete_connection_user(connection['id'], email)).to be_nil } + end + + after(:all) do + client + .connections + .select { |connection| connection['name'].include?(entity_suffix) } + .each { |connection| client.delete_connection(connection['id']) } end end diff --git a/spec/integration/lib/auth0/api/v2/api_email_spec.rb b/spec/integration/lib/auth0/api/v2/api_email_spec.rb new file mode 100644 index 00000000..afcbc903 --- /dev/null +++ b/spec/integration/lib/auth0/api/v2/api_email_spec.rb @@ -0,0 +1,71 @@ +require 'spec_helper' +describe Auth0::Api::V2::Emails do + before(:all) do + client = Auth0Client.new(v2_creds) + begin + client.delete_provider + rescue + puts 'no email provider to delete' + end + end + + let(:client) { Auth0Client.new(v2_creds) } + let(:name) { 'mandrill' } + let(:enabled) { true } + let(:credentials) { { 'api_key' => 'api_key' } } + let(:settings) { { 'first_setting' => 'first_setting_set', 'second_setting' => 'second_setting_set' } } + let(:body) do + { 'name' => name, + 'enabled' => enabled, + 'credentials' => credentials, + 'settings' => settings } + end + + describe '.configure_provider' do + let!(:email_provider) { client.configure_provider(body) } + it do + expect(email_provider).to include( + 'name' => name, 'enabled' => enabled, 'credentials' => credentials, 'settings' => settings) + end + end + + describe '.get_provider' do + let(:provider) { client.get_provider } + + it { expect(provider.size).to be > 0 } + + context '#filters' do + it do + expect( + client.get_provider(fields: [:name, :enabled, :credentials].join(','), include_fields: true)).to( + include('name', 'enabled', 'credentials')) + end + it do + expect( + client.get_provider(fields: [:enabled].join(','), include_fields: false).first).to_not(include('enabled')) + end + end + end + + describe '.update_provider' do + let(:update_name) { 'sendgrid' } + let(:update_settings) do + { 'first_up_setting' => 'first_up_setting_set', 'second_up_setting' => 'second_up_setting_set' } + end + let(:update_body) do + { 'name' => update_name, + 'settings' => update_settings } + end + it do + expect( + client.update_provider(update_body)).to( + include( + 'name' => update_name, 'enabled' => enabled, 'credentials' => credentials, 'settings' => update_settings)) + end + end + + describe '.delete_provider' do + it { expect { client.delete_provider }.to_not raise_error } + it { expect { client.get_provider }.to raise_error(Auth0::NotFound) } + end +end diff --git a/spec/integration/lib/auth0/api/v2/api_jobs_spec.rb b/spec/integration/lib/auth0/api/v2/api_jobs_spec.rb new file mode 100644 index 00000000..0216da56 --- /dev/null +++ b/spec/integration/lib/auth0/api/v2/api_jobs_spec.rb @@ -0,0 +1,69 @@ +require 'spec_helper' +describe Auth0::Api::V2::Jobs do + skip "Jobs examples are skipped to avoid Job's creation" do + let(:client) { Auth0Client.new(v2_creds) } + let(:username) { Faker::Internet.user_name } + let(:email) { "#{entity_suffix}#{Faker::Internet.safe_email(username)}" } + + describe '.import_users and .get_job' do + let(:file_content) do + [{ + 'email' => email, + 'email_verified' => false, + 'app_metadata' => { + 'roles' => ['admin'], + 'plan' => 'premium' + }, + 'user_metadata' => { + 'theme' => 'light' + } + } + ] + end + let(:users_file) do + File.new('temp.json', 'w+') { |f| f.write(file_content) } + end + let(:connection_id) do + client.connections + .find do |connection| + connection['name'].include?(Auth0::Api::AuthenticationEndpoints::UP_AUTH) + end['id'] + end + let(:imported_users) { client.import_users(users_file, connection_id) } + it do + expect(imported_users).to include( + 'connection' => Auth0::Api::AuthenticationEndpoints::UP_AUTH, + 'status' => 'pending', + 'type' => 'users_import') + end + let(:import_job_id) { imported_users['id'] } + it do + expect(client.get_job(import_job_id)).to include( + 'connection' => Auth0::Api::AuthenticationEndpoints::UP_AUTH, 'type' => 'users_import', 'id' => import_job_id) + end + end + + describe '.send_verification_email and .get_job' do + let(:user) do + client.create_user(username, 'email' => email, + 'password' => Faker::Internet.password, + 'email_verified' => false, + 'connection' => Auth0::Api::AuthenticationEndpoints::UP_AUTH, + 'app_metadata' => {}) + end + let(:email_verification_job) { client.send_verification_email(user_id: user['user_id']) } + it { expect(email_verification_job).to include('status' => 'pending', 'type' => 'verification_email') } + let(:email_job_id) { email_verification_job['id'] } + it do + expect(client.get_job(email_job_id)).to include( + 'status' => 'completed', 'type' => 'verification_email', 'id' => email_job_id) + end + end + + after(:all) do + new_client = Auth0Client.new(v2_creds) + delete_user_id = new_client.get_users(q: 'email:@example.com').first['user_id'] + new_client.delete_user(delete_user_id) + end + end +end diff --git a/spec/integration/lib/auth0/api/v2/api_rules_spec.rb b/spec/integration/lib/auth0/api/v2/api_rules_spec.rb new file mode 100644 index 00000000..38cb66fb --- /dev/null +++ b/spec/integration/lib/auth0/api/v2/api_rules_spec.rb @@ -0,0 +1,83 @@ +require 'spec_helper' +describe Auth0::Api::V2::Rules do + attr_reader :client, :enabled_rule, :disabled_rule + + before(:all) do + @client = Auth0Client.new(v2_creds) + suffix = Faker::Lorem.word + script = 'function (user, context, callback) { callback(null, user, context);}' + stage = 'login_success' + @enabled_rule = client.create_rule("Enabled Rule #{suffix}", script, rand(1..10), true, stage) + @disabled_rule = client.create_rule("Disabled Rule #{suffix}", script, rand(11..20), false, stage) + end + + after(:all) do + rules = client.rules + rules.each do |rule| + client.delete_rule(rule['id']) + end + end + + describe '.rules' do + let(:rules) { client.rules } + + it { expect(rules.size).to be > 0 } + + context '#filters' do + it do + expect(client.rules(enabled: true).size).to be 1 + end + + it do + expect(client.rules(enabled: false).size).to be 1 + end + + it do + expect(client.rules(enabled: true, fields: [:script, :order].join(',')).first).to(include('script', 'order')) + end + it do + expect(client.rules(enabled: true, fields: [:script].join(',')).first).to_not(include('order', 'name')) + end + end + end + + describe '.rule' do + it do + expect(client.rule(enabled_rule['id'])).to( + include('stage' => enabled_rule['stage'], 'order' => enabled_rule['order'], 'script' => enabled_rule['script'])) + end + + context '#filters' do + let(:rule_include) { client.rule(enabled_rule['id'], fields: [:stage, :order, :script].join(',')) } + let(:rule_not_include) { client.rule(enabled_rule['id'], fields: :stage, include_fields: false) } + + it do + expect(rule_include).to(include('stage', 'order', 'script')) + end + + it do + expect(rule_not_include).to(include('order', 'script')) + expect(rule_not_include).to_not(include('stage')) + end + end + end + + describe '.create_rule' do + let(:name) { Faker::Lorem.word } + let(:order) { rand(21..30) } + let(:stage) { 'login_success' } + let(:script) { 'function(test)' } + let(:enabled) { false } + let!(:rule) { client.create_rule(name, script, order, enabled, stage) } + it { expect(rule).to include('name' => name, 'stage' => stage, 'order' => order, 'script' => script) } + end + + describe '.delete_rule' do + it { expect { client.delete_rule(enabled_rule['id']) }.to_not raise_error } + it { expect { client.delete_rule '' }.to raise_error(Auth0::InvalidParameter) } + end + + describe '.update_rule' do + it { expect(client.update_rule(disabled_rule['id'], enabled: true)).to(include('enabled' => true)) } + end +end diff --git a/spec/integration/lib/auth0/api/v2/api_stats_spec.rb b/spec/integration/lib/auth0/api/v2/api_stats_spec.rb new file mode 100644 index 00000000..db1e79aa --- /dev/null +++ b/spec/integration/lib/auth0/api/v2/api_stats_spec.rb @@ -0,0 +1,16 @@ +require 'spec_helper' +describe Auth0::Api::V2::Stats do + let(:client) { Auth0Client.new(v2_creds) } + + describe '.active_users' do + it { expect(Integer(client.active_users)).to be >= 0 } + end + + # rubocop:disable Date + describe '.daily_stats' do + let(:from) { Date.today.prev_day.strftime('%Y%m%d') } + let(:to) { Date.today.strftime('%Y%m%d') } + let(:daily_stats) { client.daily_stats(from, to) } + it { expect(daily_stats.size).to be > 0 } + end +end diff --git a/spec/integration/lib/auth0/api/v2/api_tenants_spec.rb b/spec/integration/lib/auth0/api/v2/api_tenants_spec.rb new file mode 100644 index 00000000..a3283730 --- /dev/null +++ b/spec/integration/lib/auth0/api/v2/api_tenants_spec.rb @@ -0,0 +1,37 @@ +require 'spec_helper' +describe Auth0::Api::V2::Tenants do + attr_reader :client, :body + + before(:all) do + @client = Auth0Client.new(v2_creds) + @body = { + 'error_page' => { + 'html' => '', + 'show_log_link' => false, + 'url' => 'https://mycompany.org/error' + }, + 'friendly_name' => 'My Company', + 'picture_url' => 'https://mycompany.org/logo.png', + 'support_email' => 'support@mycompany.org', + 'support_url' => 'https://mycompany.org/support' + } + + client.update_tenant_settings(body) + end + + describe '.get_tenant_settings' do + it { expect(client.get_tenant_settings).to include(body) } + + let(:tenant_setting_fields) { client.get_tenant_settings(fields: 'picture_url') } + it { expect(tenant_setting_fields).to_not include('friendly_name' => 'My Company') } + it { expect(tenant_setting_fields).to include('picture_url' => 'https://mycompany.org/logo.png') } + end + + describe '.update_tenant_settings' do + let(:tenant_name) { Faker::Company.name } + let(:body_tenant) do + { 'friendly_name' => tenant_name } + end + it { expect(client.update_tenant_settings(body_tenant)['friendly_name']).to include(tenant_name) } + end +end diff --git a/spec/integration/lib/auth0/api/v2/api_tickets_spec.rb b/spec/integration/lib/auth0/api/v2/api_tickets_spec.rb new file mode 100644 index 00000000..51fc500a --- /dev/null +++ b/spec/integration/lib/auth0/api/v2/api_tickets_spec.rb @@ -0,0 +1,33 @@ +require 'spec_helper' +describe Auth0::Api::V2::Tickets do + attr_reader :client, :user + + before(:all) do + @client = Auth0Client.new(v2_creds) + username = Faker::Internet.user_name + email = "#{entity_suffix}#{Faker::Internet.safe_email(username)}" + password = Faker::Internet.password + @user = client.create_user(username, 'email' => email, + 'password' => password, + 'email_verified' => false, + 'connection' => Auth0::Api::AuthenticationEndpoints::UP_AUTH, + 'app_metadata' => {}) + end + + after(:all) do + client.delete_user(user['user_id']) + end + + describe '.post_email_verification' do + let(:email_verification) { client.post_email_verification(user['user_id'], result_url: 'http://myapp.com/callback') } + it { expect(email_verification).to include('ticket') } + end + + describe '.post_password_change' do + let(:password_change) do + client.post_password_change('secret', user_id: user['user_id'], + result_url: 'http://myapp.com/callback') + end + it { expect(password_change).to include('ticket') } + end +end diff --git a/spec/integration/lib/auth0/api/v2/api_users_spec.rb b/spec/integration/lib/auth0/api/v2/api_users_spec.rb index 9071804c..f9c0fc44 100644 --- a/spec/integration/lib/auth0/api/v2/api_users_spec.rb +++ b/spec/integration/lib/auth0/api/v2/api_users_spec.rb @@ -4,12 +4,11 @@ let(:username) { Faker::Internet.user_name } let(:email) { "#{entity_suffix}#{Faker::Internet.safe_email(username)}" } let(:password) { Faker::Internet.password } - let(:connection) { 'Username-Password-Authentication' } let!(:user) do client.create_user(username, 'email' => email, 'password' => password, 'email_verified' => false, - 'connection' => connection, + 'connection' => Auth0::Api::AuthenticationEndpoints::UP_AUTH, 'app_metadata' => {}) end @@ -21,10 +20,16 @@ context '#filters' do it { expect(client.users(per_page: 1).size).to be 1 } it do - expect(client.users(per_page: 1, fields: [:picture, :email, :user_id].join(',')).first).to( - include('email', 'user_id', 'picture')) + expect( + client.users(per_page: 1, fields: [:picture, :email, :user_id].join(','), include_fields: true).first + ).to(include('email', 'user_id', 'picture')) end it { expect(client.users(per_page: 1, fields: [:email].join(',')).first).to_not include('user_id', 'picture') } + it do + expect( + client.users(per_page: 1, fields: [:email].join(','), include_fields: false).first + ).to include('user_id', 'picture') + end end end @@ -32,6 +37,16 @@ let(:subject) { client.user(user['user_id']) } it { should include('email' => email, 'name' => username) } + it do + expect( + client.user(user['user_id'], fields: [:picture, :email, :user_id].join(','), include_fields: true) + ).to(include('email', 'user_id', 'picture')) + end + it do + expect( + client.user(user['user_id'], fields: [:picture, :email, :user_id].join(','), include_fields: false) + ).not_to(include('email', 'user_id', 'picture')) + end context '#filters' do it do @@ -56,5 +71,50 @@ describe '.patch_user' do it { expect(client.patch_user(user['user_id'], 'email_verified' => true)).to(include('email_verified' => true)) } + let(:body_path) do + { + 'user_metadata' => { + 'addresses' => { 'home_address' => '742 Evergreen Terrace' } + } + } + end + it do + expect( + client.patch_user(user['user_id'], body_path) + ).to(include('user_metadata' => { 'addresses' => { 'home_address' => '742 Evergreen Terrace' } })) + end + end + + describe '.link_user_account and .unlink_users_account' do + let(:email_link) { "#{entity_suffix}#{Faker::Internet.safe_email(Faker::Internet.user_name)}" } + let!(:link_user) do + client.create_user(username, 'email' => email_link, + 'password' => Faker::Internet.password, + 'email_verified' => false, + 'connection' => Auth0::Api::AuthenticationEndpoints::UP_AUTH, + 'app_metadata' => {}) + end + let(:email_primary) { "#{entity_suffix}#{Faker::Internet.safe_email(Faker::Internet.user_name)}" } + let!(:primary_user) do + client.create_user(username, 'email' => email_primary, + 'password' => Faker::Internet.password, + 'email_verified' => false, + 'connection' => Auth0::Api::AuthenticationEndpoints::UP_AUTH, + 'app_metadata' => {}) + end + + let(:body_link) { { 'provider' => 'auth0', 'user_id' => link_user['user_id'] } } + skip 'Link user account examples are skipped to avoid errors on users deletion' do + it do + expect( + client.link_user_account(primary_user['user_id'], body_link).first + ).to include('provider' => 'auth0', 'user_id' => primary_user['identities'].first['user_id']) + end + end + it do + expect( + client.unlink_users_account(primary_user['user_id'], 'auth0', link_user['user_id']).first + ).to include('provider' => 'auth0', 'user_id' => primary_user['identities'].first['user_id']) + end end end diff --git a/spec/lib/auth0/api/v2/blacklists_spec.rb b/spec/lib/auth0/api/v2/blacklists_spec.rb index 70e6b770..3e1242e9 100644 --- a/spec/lib/auth0/api/v2/blacklists_spec.rb +++ b/spec/lib/auth0/api/v2/blacklists_spec.rb @@ -9,7 +9,7 @@ context '.blacklisted_tokens' do it { expect(@instance).to respond_to(:blacklisted_tokens) } it 'is expected to call /api/v2/blacklists/tokens' do - expect(@instance).to receive(:get).with('/api/v2/blacklists/tokens') + expect(@instance).to receive(:get).with('/api/v2/blacklists/tokens', aud: nil) expect { @instance.blacklisted_tokens }.not_to raise_error end end @@ -20,5 +20,6 @@ expect(@instance).to receive(:post).with('/api/v2/blacklists/tokens', aud: 'aud', jti: 'jti') @instance.add_token_to_blacklist('jti', 'aud') end + it { expect { @instance.add_token_to_blacklist('', '') }.to raise_error 'Must specify a valid JTI' } end end diff --git a/spec/lib/auth0/api/v2/clients_spec.rb b/spec/lib/auth0/api/v2/clients_spec.rb index e5dd9c87..2ac81768 100644 --- a/spec/lib/auth0/api/v2/clients_spec.rb +++ b/spec/lib/auth0/api/v2/clients_spec.rb @@ -9,26 +9,25 @@ it { expect(@instance).to respond_to(:clients) } it { expect(@instance).to respond_to(:get_clients) } it 'is expected to send get request to /api/v2/clients/' do - expect(@instance).to receive(:get).with('/api/v2/clients', {}) + expect(@instance).to receive(:get).with('/api/v2/clients', fields: nil, include_fields: nil) expect { @instance.clients }.not_to raise_error end - it 'is expected to send get request to - /api/v2/clients?fields=name&exclude_fields=false' do - expect(@instance).to receive(:get).with('/api/v2/clients', exclude_fields: false, fields: [:name]) - expect { @instance.clients(exclude_fields: false, fields: [:name]) }.not_to raise_error + it 'is expected to send get request to /api/v2/clients?fields=name' do + expect(@instance).to receive(:get).with('/api/v2/clients', include_fields: true, fields: [:name]) + expect { @instance.clients(fields: [:name], include_fields: true) }.not_to raise_error end end context '.client' do it { expect(@instance).to respond_to(:client) } it 'is expected to send get request to /api/v2/clients/1' do - expect(@instance).to receive(:get).with('/api/v2/clients/1', {}) + expect(@instance).to receive(:get).with('/api/v2/clients/1', fields: nil, include_fields: nil) expect { @instance.client(1) }.not_to raise_error end - it 'is expected to send get request to - /api/v2/clients?fields=name&exclude_fields=false' do - expect(@instance).to receive(:get).with('/api/v2/clients/1', exclude_fields: false, fields: [:name]) - expect { @instance.client(1, exclude_fields: false, fields: [:name]) }.not_to raise_error + it 'is expected to send get request to /api/v2/clients?fields=name&include_fields=true' do + expect(@instance).to receive(:get).with('/api/v2/clients/1', include_fields: true, fields: [:name]) + expect { @instance.client(1, include_fields: true, fields: [:name]) }.not_to raise_error end + it { expect { @instance.client('') }.to raise_error 'Must specify a client id' } end context '.create_client' do @@ -37,6 +36,7 @@ expect(@instance).to receive(:post).with('/api/v2/clients', name: 'name', opt: 'opt') expect { @instance.create_client('name', name: '/name1', opt: 'opt') }.not_to raise_error end + it { expect { @instance.create_client('') }.to raise_error 'Must specify a valid client name' } end context '.delete_client' do it { expect(@instance).to respond_to(:delete_client) } @@ -44,6 +44,7 @@ expect(@instance).to receive(:delete).with('/api/v2/clients/1') expect { @instance.delete_client('1') }.not_to raise_error end + it { expect { @instance.delete_client('') }.to raise_error 'Must specify a client id' } end context '.patch_client' do @@ -52,5 +53,7 @@ expect(@instance).to receive(:patch).with('/api/v2/clients/1', fields: 'fields') expect { @instance.patch_client('1', fields: 'fields') }.not_to raise_error end + it { expect { @instance.patch_client('', nil) }.to raise_error 'Must specify a client id' } + it { expect { @instance.patch_client('some', nil) }.to raise_error 'Must specify a valid body' } end end diff --git a/spec/lib/auth0/api/v2/connections_spec.rb b/spec/lib/auth0/api/v2/connections_spec.rb index f3824ceb..2e54a5a6 100644 --- a/spec/lib/auth0/api/v2/connections_spec.rb +++ b/spec/lib/auth0/api/v2/connections_spec.rb @@ -27,16 +27,24 @@ it 'is expected to call /api/v2/connections' do body = double expect(@instance).to receive(:post).with('/api/v2/connections', body) - expect { @instance.create_connection(body) }.not_to raise_error end + + it 'is expected to raise an error when calling with empty body' do + expect(@instance).not_to receive(:post) + expect { @instance.create_connection(nil) }.to raise_error 'Must specify a body to create a connection' + end end context '.connection' do it { expect(@instance).to respond_to(:connection) } - it 'is expected to call get request to /api/v2/connection/CONNECTION_ID' do - expect(@instance).to receive(:get).with('/api/v2/connections/CONNECTION_ID', fields: nil, include_fields: true) - expect { @instance.connection('CONNECTION_ID') }.not_to raise_error + it 'is expected to call get request to /api/v2/connection/connectionId' do + expect(@instance).to receive(:get).with('/api/v2/connections/connectionId', fields: nil, include_fields: true) + expect { @instance.connection('connectionId') }.not_to raise_error + end + it 'is expected raise an error when calling with empty id' do + expect(@instance).not_to receive(:get) + expect { @instance.connection(nil) }.to raise_error 'Must supply a valid connection id' end end @@ -47,10 +55,27 @@ @instance.delete_connection('connectionId') end - it 'is expected not to call delete to /api/v2/connections - if connection_id is blank' do + it 'is expected raise an error when calling with empty id' do + expect(@instance).not_to receive(:delete) + expect { @instance.delete_connection(nil) }.to raise_error 'Must supply a valid connection id' + end + end + + context '.delete_connection_user' do + it { expect(@instance).to respond_to(:delete_connection_user) } + it 'is expected to call delete to /api/v2/connections/connectionId/users' do + expect(@instance).to receive(:delete).with('/api/v2/connections/connectionId/users?email=email@test.com') + @instance.delete_connection_user('connectionId', 'email@test.com') + end + + it 'is expected raise an error when calling with empty id' do + expect(@instance).not_to receive(:delete) + expect { @instance.delete_connection_user(nil, nil) }.to raise_error 'Must supply a valid connection id' + end + + it 'is expected raise an error when calling with empty email' do expect(@instance).not_to receive(:delete) - expect { @instance.delete_connection('') }.to raise_exception(Auth0::MissingConnectionId) + expect { @instance.delete_connection_user('Connection ID', nil) }.to raise_error 'Must supply a valid user email' end end @@ -62,10 +87,9 @@ @instance.update_connection('connectionId', body) end - it 'is expected not to call delete to /api/v2/connections - if connection_id is blank' do + it 'is expected raise an error when calling with empty id' do expect(@instance).not_to receive(:patch) - expect { @instance.delete_connection('') }.to raise_exception(Auth0::MissingConnectionId) + expect { @instance.delete_connection(nil) }.to raise_error 'Must supply a valid connection id' end end end diff --git a/spec/lib/auth0/api/v2/emails_spec.rb b/spec/lib/auth0/api/v2/emails_spec.rb new file mode 100644 index 00000000..6fceda9c --- /dev/null +++ b/spec/lib/auth0/api/v2/emails_spec.rb @@ -0,0 +1,47 @@ +require 'spec_helper' +describe Auth0::Api::V2::Emails do + before :all do + dummy_instance = DummyClass.new + dummy_instance.extend(Auth0::Api::V2::Emails) + @instance = dummy_instance + end + + context '.get_email' do + it { expect(@instance).to respond_to(:get_provider) } + it 'expect client to send get to /api/v2/emails/provider with fields' do + expect(@instance).to receive(:get).with('/api/v2/emails/provider', fields: 'some', include_fields: true) + expect { @instance.get_provider(fields: 'some', include_fields: true) }.not_to raise_error + end + it 'expect client to send get to /api/v2/emails/provider with empty fields' do + expect(@instance).to receive(:get).with('/api/v2/emails/provider', fields: nil, include_fields: nil) + expect { @instance.get_provider }.not_to raise_error + end + end + context '.configure_email' do + it { expect(@instance).to respond_to(:configure_provider) } + it 'expect client to send post to /api/v2/emails/provider' do + expect(@instance).to receive(:post).with('/api/v2/emails/provider', 'test body') + expect { @instance.configure_provider('test body') }.not_to raise_error + end + it 'expect client to raise an error when calling with empty body' do + expect { @instance.configure_provider(nil) }.to raise_error 'Must supply a valid body to create an email provider' + end + end + context '.delete_email' do + it { expect(@instance).to respond_to(:delete_provider) } + it 'expect client to send delete to /api/v2/emails/provider' do + expect(@instance).to receive(:delete).with('/api/v2/emails/provider') + expect { @instance.delete_provider }.not_to raise_error + end + end + context '.patch_email' do + it { expect(@instance).to respond_to(:update_provider) } + it 'expect client to send patch to /api/v2/emails/provider' do + expect(@instance).to receive(:patch).with('/api/v2/emails/provider', 'test body') + expect { @instance.update_provider('test body') }.not_to raise_error + end + it 'expect client to raise an error when calling with empty body' do + expect { @instance.update_provider(nil) }.to raise_error 'Must supply a valid body to update an email provider' + end + end +end diff --git a/spec/lib/auth0/api/v2/jobs_spec.rb b/spec/lib/auth0/api/v2/jobs_spec.rb index 29c1846f..7fd0db72 100644 --- a/spec/lib/auth0/api/v2/jobs_spec.rb +++ b/spec/lib/auth0/api/v2/jobs_spec.rb @@ -11,11 +11,25 @@ expect(@instance).to receive(:get).with('/api/v2/jobs/3') expect { @instance.get_job(3) }.not_to raise_error end + it { expect { @instance.get_job('') }.to raise_error('Must specify a job id') } end - context '.daily_stats' do - it { expect(@instance).to respond_to(:create_job) } - it 'expect client to send get to /api/v2/stats/daily' do - expect { @instance.create_job('file_name', 'name') }.to raise_error(NotImplementedError) + context '.import_users' do + it { expect(@instance).to respond_to(:import_users) } + it 'expect client to send post to /api/v2/jobs/users-imports' do + expect(@instance).to receive(:post_file).with( + '/api/v2/jobs/users-imports', users: 'file', connection_id: 'connnection_id') + expect { @instance.import_users('file', 'connnection_id') }.not_to raise_error end + it { expect { @instance.import_users('', 'connnection_id') }.to raise_error('Must specify a valid file') } + it { expect { @instance.import_users('users', '') }.to raise_error('Must specify a connection_id') } + end + + context '.send_verification_email' do + it { expect(@instance).to respond_to(:send_verification_email) } + it 'expect client to send post to /api/v2/jobs/verification-email' do + expect(@instance).to receive(:post).with('/api/v2/jobs/verification-email', user_id: 'user_id') + expect { @instance.send_verification_email(user_id: 'user_id') }.not_to raise_error + end + it { expect { @instance.send_verification_email('') }.to raise_error('Must specify a user id') } end end diff --git a/spec/lib/auth0/api/v2/rules_spec.rb b/spec/lib/auth0/api/v2/rules_spec.rb new file mode 100644 index 00000000..3148d49b --- /dev/null +++ b/spec/lib/auth0/api/v2/rules_spec.rb @@ -0,0 +1,69 @@ +require 'spec_helper' +describe Auth0::Api::V2::Rules do + before :all do + dummy_instance = DummyClass.new + dummy_instance.extend(Auth0::Api::V2::Rules) + dummy_instance.extend(Auth0::Mixins::Initializer) + @instance = dummy_instance + end + + context '.rules' do + it { expect(@instance).to respond_to(:rules) } + it 'is expected to call get /api/v2/rules' do + expect(@instance).to receive(:get).with( + '/api/v2/rules', enabled: nil, fields: nil, include_fields: nil, stage: nil) + expect { @instance.rules }.not_to raise_error + end + end + + context '.rule' do + it { expect(@instance).to respond_to(:rule) } + it 'is expected to call get /api/v2/rules/test' do + expect(@instance).to receive(:get).with( + '/api/v2/rules/test', fields: nil, include_fields: nil) + expect { @instance.rule('test') }.not_to raise_error + end + it 'expect to raise an error when calling with empty rule id' do + expect { @instance.rule(nil) }.to raise_error 'Must supply a valid rule id' + end + end + + context '.create_rule' do + it { expect(@instance).to respond_to(:create_rule) } + it 'is expected to call post /api/v2/rules' do + expect(@instance).to receive(:post).with( + '/api/v2/rules', + name: 'test', script: 'script', order: 'order', enabled: false, stage: 'login_success') + expect { @instance.create_rule('test', 'script', 'order', false) }.not_to raise_error + end + it 'expect to raise an error when calling with empty name' do + expect { @instance.create_rule(nil, 'script') }.to raise_error 'Must supply a valid name' + end + it 'expect to raise an error when calling with empty script' do + expect { @instance.create_rule('test', nil) }.to raise_error 'Must supply a valid script' + end + end + context '.update_rule' do + it { expect(@instance).to respond_to(:update_rule) } + it 'is expected to call put /api/v2/rules/test' do + expect(@instance).to receive(:patch).with( + '/api/v2/rules/test', script: 'script', order: 'order', enabled: true, stage: 'some_stage') + expect do + @instance.update_rule('test', script: 'script', order: 'order', enabled: true, stage: 'some_stage') + end.not_to raise_error + end + it 'expect to raise an error when calling with empty rule id' do + expect { @instance.update_rule(nil, 'test') }.to raise_error 'Must supply a valid rule id' + end + end + context '.delete_rule' do + it { expect(@instance).to respond_to(:delete_rule) } + it 'is expected to call delete /api/v2/rules/test' do + expect(@instance).to receive(:delete).with('/api/v2/rules/test') + expect { @instance.delete_rule('test') }.not_to raise_error + end + it 'expect to raise an error when calling with empty rule id' do + expect { @instance.delete_rule(nil) }.to raise_error 'Must supply a valid rule id' + end + end +end diff --git a/spec/lib/auth0/api/v2/tenants_spec.rb b/spec/lib/auth0/api/v2/tenants_spec.rb new file mode 100644 index 00000000..7085b579 --- /dev/null +++ b/spec/lib/auth0/api/v2/tenants_spec.rb @@ -0,0 +1,25 @@ +require 'spec_helper' +describe Auth0::Api::V2::Tenants do + before :all do + @instance = DummyClass.new.extend(Auth0::Api::V2::Tenants) + end + + context '.get_tenant_settings' do + it { expect(@instance).to respond_to(:get_tenant_settings) } + it 'expect client to send post to /api/v2/tenants/settings with fields' do + expect(@instance).to receive(:get).with('/api/v2/tenants/settings', fields: 'field', include_fields: true) + expect { @instance.get_tenant_settings(fields: 'field') }.not_to raise_error + end + end + context '.update_tenant_settings' do + it { expect(@instance).to respond_to(:update_tenant_settings) } + it 'expect client to send post to /api/v2/tenants/settings with body' do + expect(@instance).to receive(:patch).with('/api/v2/tenants/settings', 'test body') + expect { @instance.update_tenant_settings('test body') }.not_to raise_error + end + it 'expect client to rasie error when calling with empty body' do + expect { @instance.update_tenant_settings(nil) }.to raise_error( + 'Must supply a valid body to update tenant settings') + end + end +end diff --git a/spec/lib/auth0/api/v2/tickets_spec.rb b/spec/lib/auth0/api/v2/tickets_spec.rb new file mode 100644 index 00000000..e5f93237 --- /dev/null +++ b/spec/lib/auth0/api/v2/tickets_spec.rb @@ -0,0 +1,31 @@ +require 'spec_helper' +describe Auth0::Api::V2::Tickets do + before :all do + @instance = DummyClass.new.extend(Auth0::Api::V2::Tickets) + end + + context '.post_email_verification' do + it { expect(@instance).to respond_to(:post_email_verification) } + it 'expect client to send post to /api/v2/tickets/email-verification with body' do + expect(@instance).to receive(:post).with('/api/v2/tickets/email-verification', user_id: 'user_id', result_url: nil) + expect { @instance.post_email_verification('user_id') }.not_to raise_error + end + it 'expect client to rasie error when calling with empty body' do + expect { @instance.post_email_verification(nil) }.to raise_error( + 'Must supply a valid user id to post an email verification') + end + end + context '.post_password_change' do + it { expect(@instance).to respond_to(:post_password_change) } + it 'expect client to send post to /api/v2/tickets/password-change with body' do + expect(@instance).to receive(:post).with('/api/v2/tickets/password-change', user_id: nil, result_url: nil, + new_password: 'new_pass', + connection_id: nil, email: nil) + expect { @instance.post_password_change('new_pass') }.not_to raise_error + end + it 'expect client to rasie error when calling with empty body' do + expect { @instance.post_password_change(nil) }.to raise_error( + 'Must supply a valid new password to post a password-change') + end + end +end diff --git a/spec/lib/auth0/api/v2/users_spec.rb b/spec/lib/auth0/api/v2/users_spec.rb index fcf345ca..5a941b31 100644 --- a/spec/lib/auth0/api/v2/users_spec.rb +++ b/spec/lib/auth0/api/v2/users_spec.rb @@ -18,6 +18,7 @@ sort: nil, connection: nil, fields: nil, + include_fields: nil, q: nil) expect { @instance.users }.not_to raise_error end @@ -26,9 +27,10 @@ context '.user' do it { expect(@instance).to respond_to(:user) } it 'is expected to call get request to /api/v2/users/USER_ID' do - expect(@instance).to receive(:get).with('/api/v2/users/USER_ID', fields: nil) + expect(@instance).to receive(:get).with('/api/v2/users/USER_ID', fields: nil, include_fields: true) expect { @instance.user('USER_ID') }.not_to raise_error end + it { expect { @instance.user('') }.to raise_error 'Must supply a valid user_id' } end context '.create_user' do @@ -94,5 +96,39 @@ connection: 'conn', name: 'name') end + it { expect { @instance.patch_user('', 'body') }.to raise_error 'Must supply a valid user_id' } + it { expect { @instance.patch_user('UserId', '') }.to raise_error 'Must supply a valid body' } + end + + context '.link_user_account' do + it { expect(@instance).to respond_to(:link_user_account) } + it 'is expected to call post to /api/v2/users/UserId/identities' do + expect(@instance).to receive(:post).with('/api/v2/users/UserID/identities', body: 'json body') + @instance.link_user_account('UserID', body: 'json body') + end + it { expect { @instance.link_user_account('', 'body') }.to raise_error 'Must supply a valid user_id' } + it { expect { @instance.link_user_account('UserId', '') }.to raise_error 'Must supply a valid body' } + end + + context '.unlink_users_account' do + it { expect(@instance).to respond_to(:unlink_users_account) } + it 'is expected to call delete to /api/v2/users/UserId/identities' do + expect(@instance).to receive(:delete).with('/api/v2/users/UserID/identities/provider_name/Secondary_User_ID') + @instance.unlink_users_account('UserID', 'provider_name', 'Secondary_User_ID') + end + it { expect { @instance.unlink_users_account('', 'pro', 'SUserID') }.to raise_error 'Must supply a valid user_id' } + it { expect { @instance.unlink_users_account('UID', nil, 'SUID') }.to raise_error 'Must supply a valid provider' } + it do + expect { @instance.unlink_users_account('UID', 'pro', nil) }.to raise_error 'Must supply a valid secondary user_id' + end + end + + context '.delete_user_provider' do + it { expect(@instance).to respond_to(:delete_user_provider) } + it 'is expected to call delete to /api/v2/users/User_ID/multifactor/provider_name' do + expect(@instance).to receive(:delete).with('/api/v2/users/User_ID/multifactor/provider_name') + @instance.delete_user_provider('User_ID', 'provider_name') + end + it { expect { @instance.delete_user_provider(nil, 'test') }.to raise_error 'Must supply a valid user_id' } end end diff --git a/spec/lib/auth0/mixins/initializer_spec.rb b/spec/lib/auth0/mixins/initializer_spec.rb index 1e40f6c6..ab597e8d 100644 --- a/spec/lib/auth0/mixins/initializer_spec.rb +++ b/spec/lib/auth0/mixins/initializer_spec.rb @@ -3,7 +3,7 @@ class MockClass attr_reader :token include Auth0::Mixins::Initializer - include HTTParty + include HTTMultiParty end describe Auth0::Mixins::Initializer do diff --git a/spec/support/dummy_class_for_proxy.rb b/spec/support/dummy_class_for_proxy.rb index 3bf1510a..7e278d33 100644 --- a/spec/support/dummy_class_for_proxy.rb +++ b/spec/support/dummy_class_for_proxy.rb @@ -1,4 +1,4 @@ class DummyClassForProxy - include HTTParty + include HTTMultiParty base_uri 'http://auth0.com' end diff --git a/spec/support/import_users.json b/spec/support/import_users.json new file mode 100644 index 00000000..86469c2a --- /dev/null +++ b/spec/support/import_users.json @@ -0,0 +1,13 @@ +[ + { + "email": "john.doe@contoso.com", + "email_verified": false, + "app_metadata": { + "roles": ["admin"], + "plan": "premium" + }, + "user_metadata": { + "theme": "light" + } + } +]