Skip to content

Commit 678cd82

Browse files
authored
Merge branch 'apache:main' into main
2 parents 016ba92 + 50f664e commit 678cd82

6 files changed

Lines changed: 196 additions & 0 deletions

File tree

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/*
2+
Licensed to the Apache Software Foundation (ASF) under one or more
3+
contributor license agreements. See the NOTICE file distributed with
4+
this work for additional information regarding copyright ownership.
5+
The ASF licenses this file to You under the Apache License, Version 2.0
6+
(the "License"); you may not use this file except in compliance with
7+
the License. You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
18+
package oidchelper
19+
20+
import "strings"
21+
22+
func (c *Config) IsUserAllowed(email string) bool {
23+
if len(c.AllowEmails) == 0 &&
24+
len(c.AllowDomains) == 0 {
25+
return true
26+
}
27+
28+
email = strings.ToLower(strings.TrimSpace(email))
29+
30+
if _, ok := c.AllowEmails[email]; ok {
31+
return true
32+
}
33+
34+
_, domain, ok := strings.Cut(email, "@")
35+
if ok {
36+
if _, ok := c.AllowDomains[domain]; ok {
37+
return true
38+
}
39+
}
40+
41+
return false
42+
}
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
/*
2+
Licensed to the Apache Software Foundation (ASF) under one or more
3+
contributor license agreements. See the NOTICE file distributed with
4+
this work for additional information regarding copyright ownership.
5+
The ASF licenses this file to You under the Apache License, Version 2.0
6+
(the "License"); you may not use this file except in compliance with
7+
the License. You may obtain a copy of the License at
8+
9+
http://www.apache.org/licenses/LICENSE-2.0
10+
11+
Unless required by applicable law or agreed to in writing, software
12+
distributed under the License is distributed on an "AS IS" BASIS,
13+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14+
See the License for the specific language governing permissions and
15+
limitations under the License.
16+
*/
17+
18+
package oidchelper
19+
20+
import "testing"
21+
22+
func TestIsUserAllowed(t *testing.T) {
23+
cases := []struct {
24+
name string
25+
cfg Config
26+
email string
27+
want bool
28+
}{
29+
{
30+
name: "no restrictions",
31+
cfg: Config{},
32+
email: "user@example.com",
33+
want: true,
34+
},
35+
{
36+
name: "allowed email",
37+
cfg: Config{
38+
AllowEmails: map[string]struct{}{
39+
"user@example.com": {},
40+
},
41+
},
42+
email: "user@example.com",
43+
want: true,
44+
},
45+
{
46+
name: "blocked email",
47+
cfg: Config{
48+
AllowEmails: map[string]struct{}{
49+
"user@example.com": {},
50+
},
51+
},
52+
email: "other@example.com",
53+
want: false,
54+
},
55+
{
56+
name: "allowed domain",
57+
cfg: Config{
58+
AllowDomains: map[string]struct{}{
59+
"example.com": {},
60+
},
61+
},
62+
email: "user@example.com",
63+
want: true,
64+
},
65+
{
66+
name: "blocked domain",
67+
cfg: Config{
68+
AllowDomains: map[string]struct{}{
69+
"example.com": {},
70+
},
71+
},
72+
email: "user@other.com",
73+
want: false,
74+
},
75+
{
76+
name: "email case insensitive",
77+
cfg: Config{
78+
AllowEmails: map[string]struct{}{
79+
"user@example.com": {},
80+
},
81+
},
82+
email: "USER@example.com",
83+
want: true,
84+
},
85+
{
86+
name: "domain case insensitive",
87+
cfg: Config{
88+
AllowDomains: map[string]struct{}{
89+
"example.com": {},
90+
},
91+
},
92+
email: "user@EXAMPLE.COM",
93+
want: true,
94+
},
95+
{
96+
name: "invalid email",
97+
cfg: Config{
98+
AllowDomains: map[string]struct{}{
99+
"example.com": {},
100+
},
101+
},
102+
email: "not-an-email",
103+
want: false,
104+
},
105+
}
106+
107+
for _, tc := range cases {
108+
t.Run(tc.name, func(t *testing.T) {
109+
if got := tc.cfg.IsUserAllowed(tc.email); got != tc.want {
110+
t.Errorf(
111+
"IsUserAllowed(%q) = %v, want %v",
112+
tc.email,
113+
got,
114+
tc.want,
115+
)
116+
}
117+
})
118+
}
119+
}

backend/helpers/oidchelper/config.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,11 @@ type Config struct {
6767
Providers map[string]*ProviderConfig
6868
LogoutRedirect bool
6969

70+
// Optional OIDC authorization restrictions.
71+
// Empty means no restriction.
72+
AllowEmails map[string]struct{}
73+
AllowDomains map[string]struct{}
74+
7075
SessionSecret []byte
7176
SessionTTL time.Duration
7277

@@ -136,6 +141,8 @@ func LoadConfig(basicRes context.BasicRes) (*Config, error) {
136141
SessionTTL: ttl,
137142
CookieDomain: strings.TrimSpace(cfg.GetString("COOKIE_DOMAIN")),
138143
CookieSecure: cookieSecure,
144+
AllowEmails: parseStringSet(cfg.GetString("OIDC_ALLOW_EMAILS")),
145+
AllowDomains: parseStringSet(cfg.GetString("OIDC_ALLOW_DOMAINS")),
139146
}
140147

141148
if !out.OIDCEnabled {
@@ -205,6 +212,23 @@ func parseProviderNames(raw string) []string {
205212
seen[n] = struct{}{}
206213
out = append(out, n)
207214
}
215+
216+
return out
217+
}
218+
219+
func parseStringSet(raw string) map[string]struct{} {
220+
out := make(map[string]struct{})
221+
222+
for _, v := range strings.Split(raw, ",") {
223+
v = strings.ToLower(strings.TrimSpace(v))
224+
225+
if v == "" {
226+
continue
227+
}
228+
229+
out[v] = struct{}{}
230+
}
231+
208232
return out
209233
}
210234

backend/plugins/dbt/impl/impl.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@ func (p Dbt) GetTablesInfo() []dal.Tabler {
5252
}
5353

5454
func (p Dbt) PrepareTaskData(taskCtx plugin.TaskContext, options map[string]interface{}) (interface{}, errors.Error) {
55+
taskCtx.GetLogger().Warn(nil, "The dbt plugin is deprecated and will be removed on August 31, 2026. Please migrate to alternative transformation approaches.")
5556
var op tasks.DbtOptions
5657
err := helper.Decode(options, &op, nil)
5758
if err != nil {

backend/server/api/auth/auth.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -308,6 +308,12 @@ func (s *Service) Callback(c *gin.Context) {
308308
fail(c, http.StatusBadGateway, "extract claims", err)
309309
return
310310
}
311+
312+
if !s.cfg.IsUserAllowed(email) {
313+
fail(c, http.StatusForbidden, "user is not allowed", nil)
314+
return
315+
}
316+
311317
jti := uuid.NewString()
312318
jwt, expiresAt, err := oidchelper.IssueSession(s.cfg, jti, state.Provider, sub, email, name)
313319
if err != nil {

env.example

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -162,3 +162,7 @@ SESSION_TTL=8h
162162
COOKIE_DOMAIN=
163163
# Set to false ONLY for local HTTP development.
164164
COOKIE_SECURE=true
165+
166+
# Restrict OIDC logins to specific users or domains (comma-separated, case-insensitive)
167+
OIDC_ALLOW_EMAILS=
168+
OIDC_ALLOW_DOMAINS=

0 commit comments

Comments
 (0)