Skip to content

Commit f271c8d

Browse files
provider/github: init OIDC provider for GitHub (#1281)
GitHub has a special OIDC provider with provider ID := github. This contains a certain number of interesting special properties w.r.t. to email retrieval logic (select the primary email, etc.). It's superior to the generic OIDC one. Signed-off-by: Raito Bezarius <[email protected]>
1 parent 2bddd5b commit f271c8d

6 files changed

+603
-1
lines changed
Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
---
2+
page_title: "keycloak_oidc_github_identity_provider Resource"
3+
---
4+
5+
# keycloak\_oidc\_github\_identity\_provider Resource
6+
7+
Allows for creating and managing **GitHub**-based OIDC Identity Providers within Keycloak.
8+
9+
OIDC (OpenID Connect) identity providers allows users to authenticate through a third party system using the OIDC standard.
10+
11+
The GitHub variant is specialized for the public GitHub instance (github.com) or GitHub Enterprise deployments.
12+
13+
For example, it will obtain automatically the primary email from the logged in account.
14+
15+
## Example Usage
16+
17+
```hcl
18+
resource "keycloak_realm" "realm" {
19+
realm = "my-realm"
20+
enabled = true
21+
}
22+
23+
resource "keycloak_oidc_github_identity_provider" "github" {
24+
realm = keycloak_realm.realm.id
25+
client_id = var.github_identity_provider_client_id
26+
client_secret = var.github_identity_provider_client_secret
27+
trust_email = true
28+
sync_mode = "IMPORT"
29+
30+
extra_config = {
31+
"myCustomConfigKey" = "myValue"
32+
}
33+
}
34+
```
35+
36+
## Argument Reference
37+
38+
- `realm` - (Required) The name of the realm. This is unique across Keycloak.
39+
- `client_id` - (Required) The client or client identifier registered within the identity provider.
40+
- `client_secret` - (Required) The client or client secret registered within the identity provider. This field is able to obtain its value from vault, use $${vault.ID} format.
41+
- `alias` - (Optional) The alias for the GitHub identity provider.
42+
- `display_name` - (Optional) Display name for the GitHub identity provider in the GUI.
43+
- `enabled` - (Optional) When `true`, users will be able to log in to this realm using this identity provider. Defaults to `true`.
44+
- `store_token` - (Optional) When `true`, tokens will be stored after authenticating users. Defaults to `true`.
45+
- `add_read_token_role_on_create` - (Optional) When `true`, new users will be able to read stored tokens. This will automatically assign the `broker.read-token` role. Defaults to `false`.
46+
- `link_only` - (Optional) When `true`, users cannot sign-in using this provider, but their existing accounts will be linked when possible. Defaults to `false`.
47+
- `trust_email` - (Optional) When `true`, email addresses for users in this provider will automatically be verified regardless of the realm's email verification policy. Defaults to `false`.
48+
- `first_broker_login_flow_alias` - (Optional) The authentication flow to use when users log in for the first time through this identity provider. Defaults to `first broker login`.
49+
- `post_broker_login_flow_alias` - (Optional) The authentication flow to use after users have successfully logged in, which can be used to perform additional user verification (such as OTP checking). Defaults to an empty string, which means no post login flow will be used.
50+
- `provider_id` - (Optional) The ID of the identity provider to use. Defaults to `github`, which should be used unless you have extended Keycloak and provided your own implementation.
51+
- `base_url` - (Optional) The GitHub base URL, defaults to `https://github.com`
52+
- `api_url` - (Optional) The GitHub API URL, defaults to `https://api.github.com`.
53+
- `github_json_format` (Optional) When `true`, GitHub API is told explicitly to accept JSON during token authentication requests. Defaults to `false`.
54+
- `default_scopes` - (Optional) The scopes to be sent when asking for authorization. It can be a space-separated list of scopes. Defaults to `user:email`.
55+
- `disable_user_info` - (Optional) When `true`, disables the usage of the user info service to obtain additional user information. Defaults to `false`.
56+
- `hide_on_login_page` - (Optional) When `true`, this identity provider will be hidden on the login page. Defaults to `false`.
57+
- `sync_mode` - (Optional) The default sync mode to use for all mappers attached to this identity provider. Can be once of `IMPORT`, `FORCE`, or `LEGACY`.
58+
- `gui_order` - (Optional) A number defining the order of this identity provider in the GUI.
59+
- `extra_config` - (Optional) A map of key/value pairs to add extra configuration to this identity provider. This can be used for custom oidc provider implementations, or to add configuration that is not yet supported by this Terraform provider. Use this attribute at your own risk, as custom attributes may conflict with top-level configuration attributes in future provider updates.
60+
61+
## Attribute Reference
62+
63+
- `internal_id` - (Computed) The unique ID that Keycloak assigns to the identity provider upon creation.
64+
65+
## Import
66+
67+
GitHub Identity providers can be imported using the format {{realm_id}}/{{idp_alias}}, where idp_alias is the identity provider alias.
68+
69+
Example:
70+
71+
```bash
72+
$ terraform import keycloak_oidc_github_identity_provider.github.github_identity_provider my-realm/my-github-idp
73+
```

keycloak/identity_provider.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,9 @@ type IdentityProviderConfig struct {
5656
Issuer string `json:"issuer,omitempty"`
5757
OrgRedirectModeEmailMatches types.KeycloakBoolQuoted `json:"kc.org.broker.redirect.mode.email-matches,omitempty"`
5858
OrgDomain string `json:"kc.org.domain,omitempty"`
59+
ApiUrl string `json:"apiUrl,omitempty"`
60+
BaseUrl string `json:"baseUrl,omitempty"`
61+
GithubJsonFormat types.KeycloakBoolQuoted `json:"githubJsonFormat,omitempty"`
5962
}
6063

6164
type IdentityProvider struct {

provider/provider.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ func KeycloakProvider(client *keycloak.KeycloakClient) *schema.Provider {
102102
"keycloak_custom_identity_provider_mapper": resourceKeycloakCustomIdentityProviderMapper(),
103103
"keycloak_saml_identity_provider": resourceKeycloakSamlIdentityProvider(),
104104
"keycloak_oidc_google_identity_provider": resourceKeycloakOidcGoogleIdentityProvider(),
105+
"keycloak_oidc_github_identity_provider": resourceKeycloakOidcGithubIdentityProvider(),
105106
"keycloak_oidc_identity_provider": resourceKeycloakOidcIdentityProvider(),
106107
"keycloak_openid_client_authorization_resource": resourceKeycloakOpenidClientAuthorizationResource(),
107108
"keycloak_openid_client_group_policy": resourceKeycloakOpenidClientAuthorizationGroupPolicy(),

provider/resource_keycloak_attribute_importer_identity_provider_mapper.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -67,7 +67,7 @@ func getAttributeImporterIdentityProviderMapperFromData(ctx context.Context, dat
6767
}
6868

6969
rec.Config.Claim = data.Get("claim_name").(string)
70-
} else if identityProvider.ProviderId == "apple" || identityProvider.ProviderId == "facebook" || identityProvider.ProviderId == "google" {
70+
} else if identityProvider.ProviderId == "apple" || identityProvider.ProviderId == "facebook" || identityProvider.ProviderId == "google" || identityProvider.ProviderId == "github" {
7171
rec.IdentityProviderMapper = fmt.Sprintf("%s-user-attribute-mapper", identityProvider.ProviderId)
7272
rec.Config.JsonField = data.Get("claim_name").(string)
7373
rec.Config.UserAttributeName = data.Get("user_attribute").(string)
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
1+
package provider
2+
3+
import (
4+
"dario.cat/mergo"
5+
"github.com/hashicorp/go-version"
6+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
7+
"github.com/keycloak/terraform-provider-keycloak/keycloak"
8+
"github.com/keycloak/terraform-provider-keycloak/keycloak/types"
9+
)
10+
11+
func resourceKeycloakOidcGithubIdentityProvider() *schema.Resource {
12+
oidcGithubSchema := map[string]*schema.Schema{
13+
"alias": {
14+
Type: schema.TypeString,
15+
Optional: true,
16+
Computed: true,
17+
Description: "The alias uniquely identifies an identity provider and it is also used to build the redirect uri. In case of github this is computed and always github",
18+
},
19+
"display_name": {
20+
Type: schema.TypeString,
21+
Optional: true,
22+
Computed: true,
23+
Description: "The human-friendly name of the identity provider, used in the log in form.",
24+
},
25+
"provider_id": {
26+
Type: schema.TypeString,
27+
Optional: true,
28+
Default: "github",
29+
Description: "provider id, is always github, unless you have a extended custom implementation",
30+
},
31+
"client_id": {
32+
Type: schema.TypeString,
33+
Required: true,
34+
Description: "Client ID.",
35+
},
36+
"client_secret": {
37+
Type: schema.TypeString,
38+
Required: true,
39+
Sensitive: true,
40+
Description: "Client Secret.",
41+
},
42+
"base_url": {
43+
Type: schema.TypeString,
44+
Optional: true,
45+
Default: "https://github.com",
46+
Description: "Base URL for the GitHub instance, defaults to https://github.com",
47+
},
48+
"api_url": {
49+
Type: schema.TypeString,
50+
Optional: true,
51+
Default: "https://api.github.com",
52+
Description: "API URL for the GitHub instance, defaults to https://api.github.com",
53+
},
54+
"github_json_format": {
55+
Type: schema.TypeBool,
56+
Optional: true,
57+
Default: false,
58+
Description: "Whether GitHub API shoulds accept JSON explicitly during token authentication requests, defaults to false",
59+
},
60+
"default_scopes": { //defaultScope
61+
Type: schema.TypeString,
62+
Optional: true,
63+
Default: "user:email",
64+
Description: "The scopes to be sent when asking for authorization. See the documentation for possible values, separator and default value'. Default to 'user:email'",
65+
},
66+
"hide_on_login_page": {
67+
Type: schema.TypeBool,
68+
Optional: true,
69+
Default: false,
70+
Description: "Hide On Login Page.",
71+
},
72+
}
73+
oidcResource := resourceKeycloakIdentityProvider()
74+
oidcResource.Schema = mergeSchemas(oidcResource.Schema, oidcGithubSchema)
75+
oidcResource.CreateContext = resourceKeycloakIdentityProviderCreate(getOidcGithubIdentityProviderFromData, setOidcGithubIdentityProviderData)
76+
oidcResource.ReadContext = resourceKeycloakIdentityProviderRead(setOidcGithubIdentityProviderData)
77+
oidcResource.UpdateContext = resourceKeycloakIdentityProviderUpdate(getOidcGithubIdentityProviderFromData, setOidcGithubIdentityProviderData)
78+
return oidcResource
79+
}
80+
81+
func getOidcGithubIdentityProviderFromData(data *schema.ResourceData, keycloakVersion *version.Version) (*keycloak.IdentityProvider, error) {
82+
rec, defaultConfig := getIdentityProviderFromData(data, keycloakVersion)
83+
rec.ProviderId = data.Get("provider_id").(string)
84+
85+
aliasRaw, ok := data.GetOk("alias")
86+
if ok {
87+
rec.Alias = aliasRaw.(string)
88+
} else {
89+
rec.Alias = "github"
90+
}
91+
92+
githubOidcIdentityProviderConfig := &keycloak.IdentityProviderConfig{
93+
ClientId: data.Get("client_id").(string),
94+
ClientSecret: data.Get("client_secret").(string),
95+
DefaultScope: data.Get("default_scopes").(string),
96+
GithubJsonFormat: types.KeycloakBoolQuoted(data.Get("github_json_format").(bool)),
97+
BaseUrl: data.Get("base_url").(string),
98+
ApiUrl: data.Get("api_url").(string),
99+
100+
//since keycloak v26 moved to IdentityProvider - still here fore backward compatibility
101+
HideOnLoginPage: types.KeycloakBoolQuoted(data.Get("hide_on_login_page").(bool)),
102+
}
103+
104+
if err := mergo.Merge(githubOidcIdentityProviderConfig, defaultConfig); err != nil {
105+
return nil, err
106+
}
107+
108+
rec.Config = githubOidcIdentityProviderConfig
109+
110+
return rec, nil
111+
}
112+
113+
func setOidcGithubIdentityProviderData(data *schema.ResourceData, identityProvider *keycloak.IdentityProvider, keycloakVersion *version.Version) error {
114+
setIdentityProviderData(data, identityProvider, keycloakVersion)
115+
data.Set("provider_id", identityProvider.ProviderId)
116+
data.Set("client_id", identityProvider.Config.ClientId)
117+
data.Set("github_json_format", identityProvider.Config.GithubJsonFormat)
118+
data.Set("base_url", identityProvider.Config.BaseUrl)
119+
data.Set("api_url", identityProvider.Config.ApiUrl)
120+
data.Set("default_scopes", identityProvider.Config.DefaultScope)
121+
122+
if keycloakVersion.LessThan(keycloak.Version_26.AsVersion()) {
123+
// Since keycloak v26 the attribute "hideOnLoginPage" is not part of the identity provider config anymore!
124+
data.Set("hide_on_login_page", identityProvider.Config.HideOnLoginPage)
125+
return nil
126+
}
127+
128+
return nil
129+
}

0 commit comments

Comments
 (0)