osso 0.0.3.11 → 0.0.3.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ffe9bf4e6f4de963af60c998d318a471e1ff3e33ef5a6c544c8923de762020bc
4
- data.tar.gz: a994f84634c584268e517688ec62b61315da4fa1ab2ea05787305b34deb964f5
3
+ metadata.gz: 6e33fd333f7c329404b9a9bdeb62551629b38a8b615b6aef556bc4b4c0ca2a03
4
+ data.tar.gz: e8c21ea78f2f33e5b6497c85148ff67221949ded6c34380dcb48a6eb450d6dc6
5
5
  SHA512:
6
- metadata.gz: 6c4e301385bb83a8ca5f7d66e4a3b3383c7ea3f58f395dc83e1cbadadb2a6896e1852ed787ae9a33a37a2871c3d5c28e5f33e072b7980ad904f958e95b4addb8
7
- data.tar.gz: 8529f13cc30d05946b7fa798b117483dd20b9415d27b6caccecfff228a666b73bfd1f36ceb7e19d7977803159a56aff0eca9075cb380fe7fde3ce560a1847217
6
+ metadata.gz: 76779ec670e1a6c12589a3b2a1f319e8855ba8770a83489787d56c43bb8a23aa9a75ee9b9864dfce76f54061e3829ce639214ba5f5a4c7c8efc699e1776801a6
7
+ data.tar.gz: 356194bce279f215d58ea36e0e7e188c4ee134a4a4b55ce435fdee255caf23c39974f0b87a305e332a84b7aaf519db6ee13525beecd47117b9f9ebbd765679e3
@@ -5,4 +5,11 @@ steps:
5
5
  - bundle exec rake db:drop
6
6
  - bundle exec rake db:create
7
7
  - RACK_ENV=test bundle exec rake db:migrate
8
- - bundle exec rspec
8
+ - bundle exec rspec
9
+
10
+ - block: ":rubygems: Publish :red_button:"
11
+ branches: "main"
12
+
13
+ - name: "Push :rubygems:"
14
+ commands: "./bin/publish"
15
+ branches: "main"
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- osso (0.0.3.11)
4
+ osso (0.0.3.16)
5
5
  activesupport (>= 6.0.3.2)
6
6
  graphql
7
7
  jwt
@@ -66,7 +66,7 @@ GEM
66
66
  method_source (1.0.0)
67
67
  mini_portile2 (2.4.0)
68
68
  minitest (5.14.1)
69
- multi_json (1.14.1)
69
+ multi_json (1.15.0)
70
70
  mustermann (1.1.1)
71
71
  ruby2_keywords (~> 0.0.1)
72
72
  nokogiri (1.10.9)
@@ -0,0 +1,18 @@
1
+ #!/bin/sh
2
+ # Scriptacular - gemify.sh
3
+ # Create a Ruby gem and push it to rubygems.org
4
+ # Copyright 2013 Christopher Simpkins
5
+ # MIT License
6
+
7
+ GEM_NAME="osso-rb"
8
+ GEMSPEC_SUFFIX=".gemspec"
9
+
10
+ # run the gem build and parse for the gem release filename
11
+ GEM_BUILD_NAME=$(gem build "$GEM_NAME$GEMSPEC_SUFFIX" | awk '/File/ {print $2}' -)
12
+
13
+ if [ -z "$GEM_BUILD_NAME" ]; then
14
+ echo "The gem build failed." >&2
15
+ exit 1
16
+ fi
17
+
18
+ gem push $GEM_BUILD_NAME
@@ -12,6 +12,8 @@ module Osso
12
12
  field :create_oauth_client, mutation: Mutations::CreateOauthClient
13
13
  field :delete_enterprise_account, mutation: Mutations::DeleteEnterpriseAccount
14
14
  field :delete_oauth_client, mutation: Mutations::DeleteOauthClient
15
+ field :set_redirect_uris, mutation: Mutations::SetRedirectUris
16
+ field :regenerate_oauth_credentials, mutation: Mutations::RegenerateOauthCredentials
15
17
  end
16
18
  end
17
19
  end
@@ -12,3 +12,5 @@ require_relative 'mutations/create_enterprise_account'
12
12
  require_relative 'mutations/create_oauth_client'
13
13
  require_relative 'mutations/delete_enterprise_account'
14
14
  require_relative 'mutations/delete_oauth_client'
15
+ require_relative 'mutations/regenerate_oauth_credentials'
16
+ require_relative 'mutations/set_redirect_uris'
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module GraphQL
5
+ module Mutations
6
+ class RegenerateOauthCredentials < BaseMutation
7
+ null false
8
+
9
+ argument :id, ID, required: true
10
+
11
+ field :oauth_client, Types::OauthClient, null: false
12
+ field :errors, [String], null: false
13
+
14
+ def resolve(id:)
15
+ oauth_client = Osso::Models::OauthClient.find(id)
16
+ oauth_client.generate_secrets
17
+
18
+ return response_data(oauth_client: oauth_client) if oauth_client.save
19
+
20
+ response_error(errors: oauth_client.errors.full_messages)
21
+ end
22
+
23
+ def ready?(*)
24
+ return true if context[:scope] == :admin
25
+
26
+ raise ::GraphQL::ExecutionError, 'Only admin users may mutate OauthClients'
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Osso
4
+ module GraphQL
5
+ module Mutations
6
+ class SetRedirectUris < BaseMutation
7
+ null false
8
+
9
+ argument :id, ID, required: true
10
+ argument :redirect_uris, [Types::RedirectUrisInput], required: true
11
+
12
+ field :oauth_client, Types::OauthClient, null: true
13
+ field :errors, [String], null: false
14
+
15
+ def resolve(id:, redirect_uris:)
16
+ oauth_client = Osso::Models::OauthClient.find(id)
17
+
18
+ update_existing(oauth_client, redirect_uris)
19
+ create_new(oauth_client, redirect_uris)
20
+
21
+ response_data(oauth_client: oauth_client.reload)
22
+ rescue StandardError => e
23
+ response_error(errors: e)
24
+ end
25
+
26
+ def ready?(*)
27
+ return true if context[:scope] == :admin
28
+
29
+ raise ::GraphQL::ExecutionError, 'Only admin users may mutate OauthClients'
30
+ end
31
+
32
+ def update_existing(oauth_client, redirect_uris)
33
+ oauth_client.redirect_uris.each do |redirect|
34
+ updating_index = redirect_uris.index { |incoming| incoming[:id] == redirect.id }
35
+
36
+ if updating_index
37
+ updating = redirect_uris.delete_at(updating_index)
38
+ redirect.update(updating.to_h)
39
+ next
40
+ end
41
+
42
+ redirect.destroy
43
+ end
44
+ end
45
+
46
+ def create_new(oauth_client, redirect_uris)
47
+ redirect_uris.map do |uri|
48
+ oauth_client.redirect_uris.create(uri.to_h.without(:id))
49
+ end
50
+ end
51
+ end
52
+ end
53
+ end
54
+ end
@@ -8,12 +8,13 @@ module Osso
8
8
  argument :sort_column, String, required: false
9
9
  argument :sort_order, String, required: false
10
10
  end
11
- field :oauth_clients, null: true, resolver: Resolvers::OAuthClients
12
11
 
13
12
  field :enterprise_account, null: true, resolver: Resolvers::EnterpriseAccount do
14
13
  argument :domain, String, required: true
15
14
  end
16
15
 
16
+ field :oauth_clients, null: true, resolver: Resolvers::OAuthClients
17
+
17
18
  field(
18
19
  :identity_provider,
19
20
  Types::IdentityProvider,
@@ -22,6 +23,15 @@ module Osso
22
23
  ) do
23
24
  argument :id, ID, required: true
24
25
  end
26
+
27
+ field(
28
+ :oauth_client,
29
+ Types::OauthClient,
30
+ null: true,
31
+ resolve: ->(_obj, args, _context) { Osso::Models::OauthClient.find(args[:id]) },
32
+ ) do
33
+ argument :id, ID, required: true
34
+ end
25
35
  end
26
36
  end
27
37
  end
@@ -13,5 +13,7 @@ require_relative 'types/identity_provider_service'
13
13
  require_relative 'types/identity_provider_status'
14
14
  require_relative 'types/identity_provider'
15
15
  require_relative 'types/enterprise_account'
16
+ require_relative 'types/redirect_uri'
17
+ require_relative 'types/redirect_uri_input'
16
18
  require_relative 'types/oauth_client'
17
19
  require_relative 'types/user'
@@ -14,6 +14,7 @@ module Osso
14
14
  field :name, String, null: false
15
15
  field :client_id, String, null: false
16
16
  field :client_secret, String, null: false
17
+ field :redirect_uris, [Types::RedirectUri], null: true
17
18
 
18
19
  def client_id
19
20
  object.identifier
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'graphql'
4
+
5
+ module Osso
6
+ module GraphQL
7
+ module Types
8
+ class RedirectUri < Types::BaseObject
9
+ description 'An allowed redirect URI for an OauthClient'
10
+ implements ::GraphQL::Types::Relay::Node
11
+
12
+ global_id_field :gid
13
+ field :id, ID, null: false
14
+ field :uri, String, null: false
15
+ field :primary, Boolean, null: false
16
+
17
+ def self.authorized?(object, context)
18
+ super && context[:scope] == :admin
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,16 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'graphql'
4
+
5
+ module Osso
6
+ module GraphQL
7
+ module Types
8
+ class RedirectUrisInput < Types::BaseInputObject
9
+ description 'Attributes for creating or updating a collection of redirect URIs for an Oauth Client'
10
+ argument :id, ID, 'Database ID', required: false
11
+ argument :uri, String, 'URI value', required: true
12
+ argument :primary, Boolean, 'Whether the URI is the primary uri used in IDP initiated login', required: true
13
+ end
14
+ end
15
+ end
16
+ end
@@ -14,6 +14,8 @@ module Osso
14
14
  redirect ENV['JWT_URL']
15
15
  end
16
16
 
17
+ # use client id in payload to restrict customer
18
+ # users from accessing dev?
17
19
  def enterprise_authorized?(_domain)
18
20
  payload, _args = decode(token)
19
21
 
@@ -19,20 +19,14 @@ module Osso
19
19
  end
20
20
 
21
21
  def saml_options
22
- attributes.slice(
23
- 'domain',
24
- 'idp_cert',
25
- 'idp_sso_target_url',
26
- ).symbolize_keys
22
+ {
23
+ domain: domain,
24
+ idp_sso_target_url: sso_url,
25
+ idp_cert: sso_cert,
26
+ issuer: domain,
27
+ }
27
28
  end
28
29
 
29
- # def saml_options
30
- # raise(
31
- # NoMethodError,
32
- # '#saml_options must be defined on each provider specific subclass',
33
- # )
34
- # end
35
-
36
30
  def assertion_consumer_service_url
37
31
  [
38
32
  ENV.fetch('BASE_URL'),
@@ -9,11 +9,11 @@ module Osso
9
9
  has_many :identity_providers
10
10
  has_many :redirect_uris
11
11
 
12
- before_validation :setup, on: :create
12
+ before_validation :generate_secrets, on: :create
13
13
  validates :name, :secret, presence: true
14
14
  validates :identifier, presence: true, uniqueness: true
15
15
 
16
- def default_redirect_uri
16
+ def primary_redirect_uri
17
17
  redirect_uris.find(&:primary)
18
18
  end
19
19
 
@@ -21,9 +21,7 @@ module Osso
21
21
  redirect_uris.map(&:uri)
22
22
  end
23
23
 
24
- private
25
-
26
- def setup
24
+ def generate_secrets
27
25
  self.identifier = SecureRandom.hex(16)
28
26
  self.secret = SecureRandom.hex(32)
29
27
  end
@@ -4,17 +4,6 @@ module Osso
4
4
  module Models
5
5
  class RedirectUri < ActiveRecord::Base
6
6
  belongs_to :oauth_client
7
-
8
- # TODO
9
- # before_validation :set_primary, on: :creaet, :update
10
-
11
- private
12
-
13
- def set_primary
14
- if primary_was.true? && primary.false?
15
-
16
- end
17
- end
18
7
  end
19
8
  end
20
9
  end
@@ -36,6 +36,12 @@ module Osso
36
36
 
37
37
  erb :admin
38
38
  end
39
+
40
+ get '/config/:id' do
41
+ admin_protected!
42
+
43
+ erb :admin
44
+ end
39
45
  end
40
46
  end
41
47
  end
@@ -14,20 +14,16 @@ module Osso
14
14
  /[0-9a-f]{8}-[0-9a-f]{3,4}-[0-9a-f]{4}-[0-9a-f]{3,4}-[0-9a-f]{12}/.
15
15
  freeze
16
16
 
17
- def self.internal_redirect?(env)
18
- env['HTTP_REFERER']&.match(env['SERVER_NAME'])
19
- end
20
-
21
17
  use OmniAuth::Builder do
22
18
  OmniAuth::MultiProvider.register(
23
19
  self,
24
20
  provider_name: 'saml',
25
21
  identity_provider_id_regex: UUID_REGEXP,
26
- path_prefix: '/saml',
22
+ path_prefix: '/auth/saml',
27
23
  callback_suffix: 'callback',
28
24
  ) do |identity_provider_id, _env|
29
- provider = Models::IdentityProvider.find(identity_provider_id)
30
- provider.saml_options
25
+ Models::IdentityProvider.find(identity_provider_id).
26
+ saml_options
31
27
  end
32
28
  end
33
29
 
@@ -36,11 +32,10 @@ module Osso
36
32
  # their Identity Provider. We find or create a user record,
37
33
  # and then create an authorization code for that user. The user
38
34
  # is redirected back to your application with this code
39
- # as a URL query param, which you then exhange for an access token
35
+ # as a URL query param, which you then exchange for an access token.
40
36
  post '/saml/:id/callback' do
41
37
  provider = Models::IdentityProvider.find(params[:id])
42
- oauth_client = provider.oauth_client
43
- redirect_uri = env['redirect_uri'] || oauth_client.default_redirect_uri.uri
38
+ @oauth_client = provider.oauth_client
44
39
 
45
40
  attributes = env['omniauth.auth']&.
46
41
  extra&.
@@ -56,11 +51,29 @@ module Osso
56
51
  end
57
52
 
58
53
  authorization_code = user.authorization_codes.create!(
59
- oauth_client: oauth_client,
54
+ oauth_client: @oauth_client,
60
55
  redirect_uri: redirect_uri,
61
56
  )
62
57
 
63
- redirect(redirect_uri + "?code=#{CGI.escape(authorization_code.token)}&state=#{session[:oauth_state]}")
58
+ # Mark IDP as active
59
+
60
+ redirect(redirect_uri + "?code=#{CGI.escape(authorization_code.token)}&state=#{provider_state}")
61
+ end
62
+
63
+ def redirect_uri
64
+ return @oauth_client.primary_redirect_uri.uri if valid_idp_initiated_flow
65
+
66
+ session[:osso_oauth_redirect_uri]
67
+ end
68
+
69
+ def provider_state
70
+ return 'IDP_INITIATED' if valid_idp_initiated_flow
71
+
72
+ session[:osso_oauth_state]
73
+ end
74
+
75
+ def valid_idp_initiated_flow
76
+ !session[:osso_oauth_redirect_uri] && !session[:osso_oauth_state]
64
77
  end
65
78
  end
66
79
  end
@@ -6,7 +6,7 @@ module Osso
6
6
  class Oauth < Sinatra::Base
7
7
  include AppConfig
8
8
  register Sinatra::Namespace
9
- # rubocop:disable Metrics/BlockLength
9
+
10
10
  namespace '/oauth' do
11
11
  # Send your users here in order to being an authentication
12
12
  # flow. This flow follows the authorization grant oauth
@@ -19,11 +19,11 @@ module Osso
19
19
 
20
20
  Rack::OAuth2::Server::Authorize.new do |req, _res|
21
21
  client = Models::OauthClient.find_by!(identifier: req.client_id)
22
- req.verify_redirect_uri!(client.redirect_uri_values)
22
+ session[:osso_oauth_redirect_uri] = req.verify_redirect_uri!(client.redirect_uri_values)
23
23
  end.call(env)
24
24
 
25
25
  if @enterprise.single_provider?
26
- session[:oauth_state] = params[:state]
26
+ session[:osso_oauth_state] = params[:state]
27
27
  redirect "/auth/saml/#{@enterprise.provider.id}"
28
28
  end
29
29
 
@@ -35,9 +35,10 @@ module Osso
35
35
  return erb :error
36
36
  end
37
37
 
38
- # Exchange an authorization code token for an access token.
39
- # In addition to the token, you must include all paramaters
40
- # required by Oauth spec: redirect_uri, client ID, and client secret
38
+ # Exchange an authorization code for an access token.
39
+ # In addition to the authorization code, you must include all
40
+ # paramaters required by OAuth spec: redirect_uri, client ID,
41
+ # and client secret
41
42
  post '/token' do
42
43
  Rack::OAuth2::Server::Token.new do |req, res|
43
44
  code = Models::AuthorizationCode.
@@ -60,4 +61,3 @@ module Osso
60
61
  end
61
62
  end
62
63
  end
63
- # rubocop:enable Metrics/BlockLength
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Osso
4
- VERSION = '0.0.3.11'
4
+ VERSION = '0.0.3.16'
5
5
  end
@@ -14,4 +14,16 @@ describe Osso::Models::IdentityProvider do
14
14
  )
15
15
  end
16
16
  end
17
+
18
+ describe '#saml_options' do
19
+ it 'returns the required args' do
20
+ expect(subject.saml_options).
21
+ to match(
22
+ domain: subject.domain,
23
+ idp_cert: subject.sso_cert,
24
+ idp_sso_target_url: subject.sso_url,
25
+ issuer: subject.domain,
26
+ )
27
+ end
28
+ end
17
29
  end
@@ -3,6 +3,31 @@
3
3
  require 'spec_helper'
4
4
 
5
5
  describe Osso::Auth do
6
+ describe 'get /auth/saml/:uuid' do
7
+ describe 'for an Okta SAML provider' do
8
+ let(:enterprise) { create(:enterprise_with_okta) }
9
+ let(:okta_provider) { enterprise.identity_providers.first }
10
+ it 'uses omniauth saml' do
11
+ get("/auth/saml/#{okta_provider.id}")
12
+
13
+ expect(last_response).to be_redirect
14
+ follow_redirect!
15
+ expect(last_request.url).to match("auth/saml/#{okta_provider.id}")
16
+ end
17
+ end
18
+
19
+ describe 'for an Azure SAML provider' do
20
+ let(:enterprise) { create(:enterprise_with_okta) }
21
+ let(:azure_provider) { enterprise.identity_providers.first }
22
+ it 'uses omniauth saml' do
23
+ get("/auth/saml/#{azure_provider.id}")
24
+
25
+ expect(last_response).to be_redirect
26
+ follow_redirect!
27
+ expect(last_request.url).to match("auth/saml/#{azure_provider.id}")
28
+ end
29
+ end
30
+ end
6
31
  describe 'post /auth/saml/:uuid/callback' do
7
32
  describe 'for an Okta SAML provider' do
8
33
  let(:enterprise) { create(:enterprise_with_okta) }
@@ -38,6 +63,24 @@ describe Osso::Auth do
38
63
  )
39
64
  end.to change { Osso::Models::AuthorizationCode.count }.by(1)
40
65
  end
66
+
67
+ describe 'for an IDP initiated login' do
68
+ it 'redirects with a default state' do
69
+ mock_saml_omniauth
70
+
71
+ post(
72
+ "/auth/saml/#{okta_provider.id}/callback",
73
+ nil,
74
+ {
75
+ 'omniauth.auth' => OmniAuth.config.mock_auth[:saml],
76
+ 'identity_provider' => okta_provider,
77
+ },
78
+ )
79
+ expect(last_response).to be_redirect
80
+ follow_redirect!
81
+ expect(last_request.url).to match(/.*state=IDP_INITIATED$/)
82
+ end
83
+ end
41
84
  end
42
85
 
43
86
  describe 'on subsequent authentications' do
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: osso
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3.11
4
+ version: 0.0.3.16
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Bauch
8
- autorequire:
8
+ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2020-07-27 00:00:00.000000000 Z
11
+ date: 2020-08-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activesupport
@@ -226,6 +226,7 @@ email:
226
226
  executables:
227
227
  - annotate
228
228
  - console
229
+ - publish
229
230
  - setup
230
231
  extensions: []
231
232
  extra_rdoc_files: []
@@ -246,6 +247,7 @@ files:
246
247
  - Rakefile
247
248
  - bin/annotate
248
249
  - bin/console
250
+ - bin/publish
249
251
  - bin/setup
250
252
  - config/database.yml
251
253
  - db/schema.rb
@@ -278,6 +280,8 @@ files:
278
280
  - lib/osso/graphql/mutations/create_oauth_client.rb
279
281
  - lib/osso/graphql/mutations/delete_enterprise_account.rb
280
282
  - lib/osso/graphql/mutations/delete_oauth_client.rb
283
+ - lib/osso/graphql/mutations/regenerate_oauth_credentials.rb
284
+ - lib/osso/graphql/mutations/set_redirect_uris.rb
281
285
  - lib/osso/graphql/query.rb
282
286
  - lib/osso/graphql/resolvers.rb
283
287
  - lib/osso/graphql/resolvers/enterprise_account.rb
@@ -294,6 +298,8 @@ files:
294
298
  - lib/osso/graphql/types/identity_provider_service.rb
295
299
  - lib/osso/graphql/types/identity_provider_status.rb
296
300
  - lib/osso/graphql/types/oauth_client.rb
301
+ - lib/osso/graphql/types/redirect_uri.rb
302
+ - lib/osso/graphql/types/redirect_uri_input.rb
297
303
  - lib/osso/graphql/types/user.rb
298
304
  - lib/osso/helpers/auth.rb
299
305
  - lib/osso/helpers/helpers.rb
@@ -348,7 +354,7 @@ homepage: https://github.com/enterprise-oss/osso-rb
348
354
  licenses:
349
355
  - MIT
350
356
  metadata: {}
351
- post_install_message:
357
+ post_install_message:
352
358
  rdoc_options: []
353
359
  require_paths:
354
360
  - lib
@@ -364,7 +370,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
364
370
  version: '0'
365
371
  requirements: []
366
372
  rubygems_version: 3.0.3
367
- signing_key:
373
+ signing_key:
368
374
  specification_version: 4
369
375
  summary: Main functionality for Osso
370
376
  test_files: []