Skip to content

Commit 70f2ce8

Browse files
authored
Merge pull request #79 from pushkar-gr/fix/oicd-frontend
Fix/oicd frontend
2 parents eaa9413 + f175b6b commit 70f2ce8

11 files changed

Lines changed: 130 additions & 37 deletions

File tree

‎agent/Cargo.toml‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[package]
22
name = "aegis-agent"
3-
version = "1.2.1"
3+
version = "1.2.2"
44
edition = "2024"
55

66
[dependencies]

‎controller/internal/handler/oidc_handler.go‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -137,6 +137,12 @@ func (h *OIDCHandler) Callback(c *gin.Context) {
137137
provider, _ := h.oidcManager.GetProvider(providerName)
138138
roleName := provider.MapClaimsToRole(userInfo.Email, userInfo.Groups)
139139

140+
if roleName == "" || roleName == "none" {
141+
log.Printf("[oidc] login denied for user '%s' via %s: no role mapping and no default role", userInfo.Email, providerName)
142+
c.JSON(http.StatusForbidden, gin.H{"error": "Access denied: no role assigned"})
143+
return
144+
}
145+
140146
user, err := h.getOrCreateOIDCUser(userInfo, providerName, roleName)
141147
if err != nil {
142148
log.Printf("[oidc] failed to get or create user: %v", err)

‎controller/internal/oidc/oidc.go‎

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -44,10 +44,6 @@ func NewOIDCManager(ctx context.Context, googleClientID, googleSecret, githubCli
4444
return nil, fmt.Errorf("failed to parse role mapping rules: %w", err)
4545
}
4646

47-
if roleMapping.DefaultRole == "" {
48-
roleMapping.DefaultRole = "user"
49-
}
50-
5147
if googleClientID != "" && googleSecret != "" {
5248
googleProvider, err := oidc.NewProvider(ctx, "https://accounts.google.com")
5349
if err != nil {

‎controller/internal/oidc/oidc_test.go‎

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -145,6 +145,84 @@ func TestOIDCManagerGetProvider(t *testing.T) {
145145
}
146146
}
147147

148+
func TestMapClaimsToRole(t *testing.T) {
149+
tests := []struct {
150+
name string
151+
mapping RoleMappingRules
152+
email string
153+
groups []string
154+
expectedRole string
155+
}{
156+
{
157+
name: "Exact email match",
158+
mapping: RoleMappingRules{
159+
DomainMappings: map[string]string{"admin@company.com": "admin"},
160+
DefaultRole: "user",
161+
},
162+
email: "admin@company.com",
163+
expectedRole: "admin",
164+
},
165+
{
166+
name: "Domain match",
167+
mapping: RoleMappingRules{
168+
DomainMappings: map[string]string{"@company.com": "user"},
169+
DefaultRole: "none",
170+
},
171+
email: "someone@company.com",
172+
expectedRole: "user",
173+
},
174+
{
175+
name: "Group match",
176+
mapping: RoleMappingRules{
177+
GroupMappings: map[string]string{"devs": "developer"},
178+
DefaultRole: "none",
179+
},
180+
email: "user@other.com",
181+
groups: []string{"devs"},
182+
expectedRole: "developer",
183+
},
184+
{
185+
name: "No match, default_role is none",
186+
mapping: RoleMappingRules{
187+
DomainMappings: map[string]string{"@company.com": "user"},
188+
DefaultRole: "none",
189+
},
190+
email: "outsider@other.com",
191+
expectedRole: "none",
192+
},
193+
{
194+
name: "No match, default_role is empty",
195+
mapping: RoleMappingRules{
196+
DomainMappings: map[string]string{"@company.com": "user"},
197+
},
198+
email: "outsider@other.com",
199+
expectedRole: "",
200+
},
201+
{
202+
name: "No match, falls back to default role",
203+
mapping: RoleMappingRules{
204+
DomainMappings: map[string]string{"@company.com": "user"},
205+
DefaultRole: "guest",
206+
},
207+
email: "outsider@other.com",
208+
expectedRole: "guest",
209+
},
210+
}
211+
212+
for _, tt := range tests {
213+
t.Run(tt.name, func(t *testing.T) {
214+
provider := &Provider{
215+
Name: "test",
216+
RoleMapping: &tt.mapping,
217+
}
218+
role := provider.MapClaimsToRole(tt.email, tt.groups)
219+
if role != tt.expectedRole {
220+
t.Errorf("Expected role %q, got %q", tt.expectedRole, role)
221+
}
222+
})
223+
}
224+
}
225+
148226
func TestProviderConfiguration(t *testing.T) {
149227
ctx := context.Background()
150228
roleMappingJSON := `{

‎controller/static/js/api.js‎

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ const API = {
2525
localStorage.removeItem('currentUser');
2626
localStorage.removeItem('userRole');
2727

28-
if (!endpoint.includes('/auth/login')) {
28+
if (!endpoint.includes('/auth/login') && !onLoginPage) {
2929
window.location.href = '/static/pages/login.html';
3030
return null;
3131
}
@@ -190,12 +190,18 @@ function getUserRole() {
190190
return localStorage.getItem('userRole');
191191
}
192192

193-
// Check if user is authenticated (Client-side check)
194-
function requireAuth() {
193+
// Check if user is authenticated. Falls back to a server-side check for OIDC
194+
// users who have a valid HttpOnly cookie but no localStorage entry.
195+
async function requireAuth() {
195196
const user = getCurrentUser();
196-
if (!user) {
197-
window.location.href = '/static/pages/login.html';
198-
return false;
197+
if (user) return true;
198+
199+
try {
200+
const me = await API.getCurrentUser();
201+
if (me && me.username) return true;
202+
} catch (e) {
203+
// Not authenticated
199204
}
200-
return true;
205+
window.location.href = '/static/pages/login.html';
206+
return false;
201207
}

‎controller/static/pages/dashboard.html‎

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
<div class="bg-center bg-no-repeat aspect-square bg-cover rounded-full size-10 shadow-[0_0_10px_rgba(19,236,91,0.2)]" style='background-image: url("https://lh3.googleusercontent.com/aida-public/AB6AXuACmoSgB1qBq-DPKenfjridVaJFpFlsBLLqZxuUXAIwcKYmF7gxA8yPUbNJ_fuDo_xIJpgmluRIhaACm6zSFojQhnxJKk2GiyNFNT_MJPvJAXYrupDJ5-2rjk2_K3L1LUjhRiCGUC-DS1zG6mMCwSHRPTKBDemhq3dsIUB4s5pVg-OSdckm0OdaaM5UadVT9Oo7E2HQpD9wOhjbSv2RtKfLyrRF7s75q5a947f3FIMy00JnlLw7hxxZPEvcjKjDfr4M40VFlb-QCg");'></div>
4949
<div class="flex flex-col">
5050
<h1 class="text-white text-lg font-bold leading-tight tracking-tight">Service Dash</h1>
51-
<p class="text-primary text-xs font-mono font-medium">v1.2.1-aegis</p>
51+
<p class="text-primary text-xs font-mono font-medium">v1.2.2-aegis</p>
5252
</div>
5353
</div>
5454
<nav class="flex flex-col gap-2 px-4 mt-4 flex-1">
@@ -163,11 +163,9 @@ <h3 class="text-lg font-bold text-white">No Services Found</h3>
163163
let selectedServices = [];
164164
let searchQuery = '';
165165

166-
if (!requireAuth()) {
167-
// Will redirect in requireAuth
168-
}
169-
170166
document.addEventListener('DOMContentLoaded', async () => {
167+
if (!await requireAuth()) return;
168+
171169
const user = getCurrentUser();
172170
const role = getUserRole();
173171

‎controller/static/pages/login.html‎

Lines changed: 17 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -163,12 +163,6 @@ <h2 class="text-3xl font-bold text-white tracking-tight">Welcome back</h2>
163163

164164
<script src="/static/js/api.js"></script>
165165
<script>
166-
// Redirect if already logged in
167-
if (getCurrentUser()) {
168-
window.location.href = '/static/pages/dashboard.html';
169-
}
170-
171-
// Load OIDC providers on page load
172166
async function loadOIDCProviders() {
173167
try {
174168
const response = await API.getOIDCProviders();
@@ -218,8 +212,23 @@ <h2 class="text-3xl font-bold text-white tracking-tight">Welcome back</h2>
218212
return button;
219213
}
220214

221-
// Load OIDC providers
222-
loadOIDCProviders();
215+
// Redirect if already logged in (localStorage or valid OIDC cookie)
216+
(async () => {
217+
if (getCurrentUser()) {
218+
window.location.href = '/static/pages/dashboard.html';
219+
return;
220+
}
221+
try {
222+
const me = await API.getCurrentUser();
223+
if (me && me.username) {
224+
window.location.href = '/static/pages/dashboard.html';
225+
return;
226+
}
227+
} catch (e) {
228+
// Not logged in — show login form
229+
}
230+
loadOIDCProviders();
231+
})();
223232

224233
document.getElementById('loginForm').addEventListener('submit', async (e) => {
225234
e.preventDefault();

‎controller/static/pages/reset-password.html‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,9 +113,9 @@ <h2 class="text-3xl font-bold text-white tracking-tight">Reset Password</h2>
113113
<script src="/static/js/api.js"></script>
114114
<script src="/static/js/components.js"></script>
115115
<script>
116-
if (!requireAuth()) {
117-
// API.js handles redirection
118-
}
116+
(async () => {
117+
if (!await requireAuth()) return;
118+
})();
119119

120120
document.getElementById('resetPasswordForm').addEventListener('submit', async (e) => {
121121
e.preventDefault();

‎controller/static/pages/roles.html‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@
5252
<div class="bg-center bg-no-repeat aspect-square bg-cover rounded-full size-10 shadow-[0_0_10px_rgba(19,236,91,0.2)]" style='background-image: url("https://lh3.googleusercontent.com/aida-public/AB6AXuACmoSgB1qBq-DPKenfjridVaJFpFlsBLLqZxuUXAIwcKYmF7gxA8yPUbNJ_fuDo_xIJpgmluRIhaACm6zSFojQhnxJKk2GiyNFNT_MJPvJAXYrupDJ5-2rjk2_K3L1LUjhRiCGUC-DS1zG6mMCwSHRPTKBDemhq3dsIUB4s5pVg-OSdckm0OdaaM5UadVT9Oo7E2HQpD9wOhjbSv2RtKfLyrRF7s75q5a947f3FIMy00JnlLw7hxxZPEvcjKjDfr4M40VFlb-QCg");'></div>
5353
<div class="flex flex-col">
5454
<h1 class="text-white text-lg font-bold leading-tight tracking-tight">Service Dash</h1>
55-
<p class="text-primary text-xs font-mono font-medium">v1.2.1-aegis</p>
55+
<p class="text-primary text-xs font-mono font-medium">v1.2.2-aegis</p>
5656
</div>
5757
</div>
5858
<nav class="flex flex-col gap-2 px-4 mt-4 flex-1">
@@ -176,9 +176,9 @@ <h3 class="text-lg font-bold text-white flex items-center gap-2">
176176
let allServices = [];
177177
let roleServicesMap = {};
178178

179-
if (!requireAuth()) {}
180-
181179
document.addEventListener('DOMContentLoaded', async () => {
180+
if (!await requireAuth()) return;
181+
182182
const user = getCurrentUser();
183183
const role = getUserRole();
184184

‎controller/static/pages/services.html‎

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
<div class="bg-center bg-no-repeat aspect-square bg-cover rounded-full size-10 shadow-[0_0_10px_rgba(19,236,91,0.2)]" style='background-image: url("https://lh3.googleusercontent.com/aida-public/AB6AXuACmoSgB1qBq-DPKenfjridVaJFpFlsBLLqZxuUXAIwcKYmF7gxA8yPUbNJ_fuDo_xIJpgmluRIhaACm6zSFojQhnxJKk2GiyNFNT_MJPvJAXYrupDJ5-2rjk2_K3L1LUjhRiCGUC-DS1zG6mMCwSHRPTKBDemhq3dsIUB4s5pVg-OSdckm0OdaaM5UadVT9Oo7E2HQpD9wOhjbSv2RtKfLyrRF7s75q5a947f3FIMy00JnlLw7hxxZPEvcjKjDfr4M40VFlb-QCg");'></div>
6969
<div class="flex flex-col">
7070
<h1 class="text-white text-lg font-bold leading-tight tracking-tight">Service Dash</h1>
71-
<p class="text-primary text-xs font-mono font-medium">v1.2.1-aegis</p>
71+
<p class="text-primary text-xs font-mono font-medium">v1.2.2-aegis</p>
7272
</div>
7373
</div>
7474
<nav class="flex flex-col gap-2 px-4 mt-4 flex-1">
@@ -217,9 +217,9 @@ <h3 class="text-lg font-bold text-white flex items-center gap-2">
217217
<script>
218218
let services = [];
219219

220-
if (!requireAuth()) {}
221-
222220
document.addEventListener('DOMContentLoaded', async () => {
221+
if (!await requireAuth()) return;
222+
223223
const user = getCurrentUser();
224224
const role = getUserRole();
225225

0 commit comments

Comments
 (0)