Skip to content

Commit fe73ec0

Browse files
authored
Merge pull request #746 from code0-tech/648-missing-identities-provider-in-graphql-schema
Add missing identity providers validations and types
2 parents ed84045 + 4b26531 commit fe73ec0

20 files changed

+422
-2
lines changed

app/graphql/types/application_settings_type.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,5 +16,9 @@ class ApplicationSettingsType < Types::BaseObject
1616
field :admin_status_visible, Boolean,
1717
null: false,
1818
description: 'Shows if admin status can be queried by non-administrators'
19+
20+
field :identity_providers, Types::IdentityProviderType.connection_type,
21+
null: false,
22+
description: 'List of configured identity providers'
1923
end
2024
end
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
# frozen_string_literal: true
2+
3+
module Types
4+
class IdentityProviderConfigType < Types::BaseUnion
5+
description 'Represents the configuration of an identity provider.'
6+
7+
possible_types Types::OidcIdentityProviderConfigType, Types::SamlIdentityProviderConfigType
8+
9+
def self.resolve_type(object, _context)
10+
case object[:type]
11+
when :saml
12+
Types::SamlIdentityProviderConfigType
13+
else
14+
Types::OidcIdentityProviderConfigType
15+
end
16+
end
17+
end
18+
end
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
# frozen_string_literal: true
2+
3+
module Types
4+
class IdentityProviderType < Types::BaseObject
5+
description 'Represents an identity provider configuration.'
6+
7+
field :id, String, null: false, description: 'Unique identifier of the identity provider.'
8+
field :type, Types::IdentityProviderTypeEnum, null: false, description: 'Type of the identity provider.'
9+
10+
field :config, Types::IdentityProviderConfigType, null: false,
11+
description: 'Configuration details of the identity provider.'
12+
13+
def config
14+
object.config.merge(type: object.type)
15+
end
16+
end
17+
end
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# frozen_string_literal: true
2+
3+
module Types
4+
class IdentityProviderTypeEnum < Types::BaseEnum
5+
description 'The available identity provider types.'
6+
7+
Code0::Identities::Provider.constants.each do |provider_class|
8+
next if provider_class == :BaseOauth
9+
10+
provider_type = provider_class.to_s.downcase
11+
value provider_type.upcase, "Identity provider of type #{provider_type}", value: provider_type.to_sym
12+
end
13+
end
14+
end
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
# frozen_string_literal: true
2+
3+
module Types
4+
module Input
5+
class IdentityProviderConfigInputType < Types::BaseInputObject
6+
description 'Input for identity provider configuration. Contains fields for both OIDC and SAML.'
7+
8+
# OIDC fields
9+
argument :authorization_url, String, required: false,
10+
description: 'The authorization URL for the OIDC identity provider'
11+
argument :client_id, String, required: false, description: 'The client ID for the OIDC identity provider'
12+
argument :client_secret, String, required: false, description: 'The client secret for the OIDC identity provider'
13+
argument :redirect_uri, String, required: false, description: 'The redirect URI for the OIDC identity provider'
14+
argument :user_details_url, String, required: false,
15+
description: 'The user details URL for the OIDC identity provider'
16+
17+
# Common
18+
argument :attribute_statements, GraphQL::Types::JSON,
19+
required: false,
20+
description: 'List of attribute statements for the identity provider'
21+
argument :provider_name, String,
22+
required: false,
23+
description: 'The name of the identity provider'
24+
25+
# SAML-specific fields
26+
argument :metadata_url, String, required: false,
27+
description: 'Optional metadata URL to fetch metadata (alternative to settings)'
28+
argument :response_settings, GraphQL::Types::JSON,
29+
required: false,
30+
description: 'The SAML response settings for the identity provider'
31+
argument :settings, GraphQL::Types::JSON, required: false,
32+
description: 'The SAML settings for the identity provider'
33+
end
34+
end
35+
end
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# frozen_string_literal: true
2+
3+
module Types
4+
module Input
5+
class IdentityProviderInputType < Types::BaseInputObject
6+
description 'Input for creating or updating an identity provider'
7+
8+
argument :config, Types::Input::IdentityProviderConfigInputType,
9+
required: true,
10+
description: 'Configuration for the identity provider'
11+
argument :id, String, required: true, description: 'Unique identifier of the identity provider'
12+
argument :type, Types::IdentityProviderTypeEnum, required: true, description: 'Type of the identity provider'
13+
end
14+
end
15+
end
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
# frozen_string_literal: true
2+
3+
module Types
4+
class OidcIdentityProviderConfigType < Types::BaseObject
5+
description 'Represents an OIDC identity provider configuration'
6+
7+
markdown_documentation <<~MARKDOWN
8+
For more information see: https://github.com/code0-tech/code0-identities/blob/#{Code0::Identities::VERSION}/README.md#oauth-based
9+
MARKDOWN
10+
11+
# rubocop:disable Graphql/ExtractType
12+
field :client_id, String,
13+
null: false,
14+
description: 'The client ID for the OIDC identity provider'
15+
16+
field :client_secret, String,
17+
null: false,
18+
description: 'The client secret for the OIDC identity provider'
19+
# rubocop:enable Graphql/ExtractType
20+
21+
field :redirect_uri, String,
22+
null: false,
23+
description: 'The redirect URI for the OIDC identity provider'
24+
25+
field :provider_name, String,
26+
null: false,
27+
description: 'The name of the OIDC identity provider'
28+
29+
field :user_details_url, String,
30+
null: false,
31+
description: 'The user details URL for the OIDC identity provider'
32+
33+
field :authorization_url, String,
34+
null: false,
35+
description: 'The authorization URL for the OIDC identity provider'
36+
37+
field :attribute_statements, GraphQL::Types::JSON,
38+
null: false,
39+
description: 'List of attribute statements for the OIDC identity provider'
40+
end
41+
end
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
# frozen_string_literal: true
2+
3+
module Types
4+
class SamlIdentityProviderConfigType < Types::BaseObject
5+
description 'Represents the configuration for a SAML identity provider.'
6+
7+
markdown_documentation <<~MARKDOWN
8+
For more information see: https://github.com/code0-tech/code0-identities/blob/#{Code0::Identities::VERSION}/README.md#saml
9+
MARKDOWN
10+
11+
field :provider_name, String,
12+
null: false,
13+
description: 'The name of the SAML identity provider'
14+
15+
field :attribute_statements, GraphQL::Types::JSON,
16+
null: false,
17+
description: 'List of attribute statements for the SAML identity provider'
18+
19+
field :settings, GraphQL::Types::JSON,
20+
null: false,
21+
description: 'The SAML settings for the identity provider'
22+
23+
field :response_settings, GraphQL::Types::JSON,
24+
null: false,
25+
description: 'The SAML response settings for the identity provider'
26+
27+
field :metadata_url, String,
28+
null: true,
29+
description: 'The metadata url to fetch the metadatas (replacement for settings)'
30+
end
31+
end

app/models/application_setting.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ class ApplicationSetting < ApplicationRecord
2525
}
2626
validate :validate_value
2727

28+
validate :validate_identity_providers, if: :identity_providers?
29+
2830
BOOLEAN_OPTIONS.each do |option|
2931
validates :value, inclusion: { in: [false, true] }, if: :"#{option}?"
3032
end
@@ -33,6 +35,28 @@ def validate_value
3335
errors.add(:value, :blank) if value.nil?
3436
end
3537

38+
def validate_identity_providers
39+
value.each do |provider|
40+
provider.deep_symbolize_keys!
41+
if provider[:id].nil? || provider[:type].nil? || provider[:config].nil?
42+
next errors.add(:value, :id_type_or_config_missing)
43+
end
44+
45+
if provider[:type] == 'saml'
46+
allowed_keys = %i[provider_name attribute_statements settings response_settings metadata_url]
47+
errors.add(:value, :invalid_saml_configuration_keys) unless (provider[:config].keys - allowed_keys).empty?
48+
else
49+
required_keys = %i[client_id client_secret redirect_uri user_details_url authorization_url]
50+
allowed_keys = %i[provider_name attribute_statements] + required_keys
51+
52+
required_keys -= %i[user_details_url authorization_url] unless provider[:type] == 'oidc'
53+
54+
errors.add(:value, :invalid_oidc_configuration_keys) unless (provider[:config].keys - allowed_keys).empty?
55+
errors.add(:value, :missing_oidc_configuration_keys) unless (required_keys - provider[:config].keys).empty?
56+
end
57+
end
58+
end
59+
3660
def self.assert_settings_present!(records = ApplicationSetting.all)
3761
missing_settings = SETTINGS.keys - records.map(&:setting)
3862
return if missing_settings.empty?
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
---
2+
title: IdentityProviderType
3+
---
4+
5+
The available identity provider types.
6+
7+
| Value | Description |
8+
|-------|-------------|
9+
| `DISCORD` | Identity provider of type discord |
10+
| `GITHUB` | Identity provider of type github |
11+
| `GOOGLE` | Identity provider of type google |
12+
| `MICROSOFT` | Identity provider of type microsoft |
13+
| `OIDC` | Identity provider of type oidc |
14+
| `SAML` | Identity provider of type saml |

0 commit comments

Comments
 (0)