diff --git a/go.mod b/go.mod index 3ae25f6..f41f20d 100644 --- a/go.mod +++ b/go.mod @@ -16,7 +16,7 @@ require ( github.com/go-jose/go-jose/v4 v4.1.3 // indirect github.com/golang-jwt/jwt/v5 v5.3.1 // indirect github.com/google/uuid v1.6.0 // indirect - github.com/in4it/go-devops-platform v0.1.7 + github.com/in4it/go-devops-platform v0.1.8 github.com/russellhaering/gosaml2 v0.10.0 // indirect github.com/russellhaering/goxmldsig v1.5.0 // indirect ) diff --git a/go.sum b/go.sum index 72f9056..cb602a4 100644 --- a/go.sum +++ b/go.sum @@ -5,24 +5,16 @@ github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-jose/go-jose/v4 v4.1.3 h1:CVLmWDhDVRa6Mi/IgCgaopNosCaHz7zrMeF9MlZRkrs= github.com/go-jose/go-jose/v4 v4.1.3/go.mod h1:x4oUasVrzR7071A4TnHLGSPpNOm2a21K9Kf04k1rs08= -github.com/golang-jwt/jwt/v5 v5.3.0 h1:pv4AsKCKKZuqlgs5sUmn4x8UlGa0kEVt/puTpKx9vvo= -github.com/golang-jwt/jwt/v5 v5.3.0/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/golang-jwt/jwt/v5 v5.3.1 h1:kYf81DTWFe7t+1VvL7eS+jKFVWaUnK9cB1qbwn63YCY= github.com/golang-jwt/jwt/v5 v5.3.1/go.mod h1:fxCRLWMO43lRc8nhHWY6LGqRcf+1gQWArsqaEUEa5bE= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= -github.com/gopacket/gopacket v1.4.0 h1:cr1OlFpzksCkZHNO0eLjaSSOrMQnpPXg0j6qHIY3y2U= -github.com/gopacket/gopacket v1.4.0/go.mod h1:EpvsxINeehp5qj4YMKMLf2/dekdhKn2IIAO/ZOifS7o= github.com/gopacket/gopacket v1.5.0 h1:9s9fcSUVKFlRV97B77Bq9XNV3ly2gvvsneFMQUGjc+M= github.com/gopacket/gopacket v1.5.0/go.mod h1:i3NaGaqfoWKAr1+g7qxEdWsmfT+MXuWkAe9+THv8LME= -github.com/in4it/go-devops-platform v0.1.6 h1:vZkb5yztBhC5I4Mf+iLuOPNS6quOgIk+UiG6gQqjXyw= -github.com/in4it/go-devops-platform v0.1.6/go.mod h1:e8XwPp/yHjKTZquS5BPytSesZcAxq1dHFofHuVlRw8g= -github.com/in4it/go-devops-platform v0.1.7-0.20260210202834-8e3f0f785633 h1:NdIM+YkTu2mcVh5gGGnM8aToFUuN/H5So+1rEFc51Pg= -github.com/in4it/go-devops-platform v0.1.7-0.20260210202834-8e3f0f785633/go.mod h1:e8XwPp/yHjKTZquS5BPytSesZcAxq1dHFofHuVlRw8g= -github.com/in4it/go-devops-platform v0.1.7 h1:Bd5t84N9qI98ysQNcjZyzGZ6iloKXV+79x0NtmSh1eU= -github.com/in4it/go-devops-platform v0.1.7/go.mod h1:rCxubxHYzF6idIN7V4xED2ytXGdNbQAJZjeEPgQzZxw= +github.com/in4it/go-devops-platform v0.1.8 h1:OGGsfj7KTvrcyCG0Rqh2bHnlAbdRxr9/B56i6jecM+8= +github.com/in4it/go-devops-platform v0.1.8/go.mod h1:rCxubxHYzF6idIN7V4xED2ytXGdNbQAJZjeEPgQzZxw= github.com/jonboulle/clockwork v0.5.0 h1:Hyh9A8u51kptdkR+cqRpT1EebBwTn1oK9YfGYbdFz6I= github.com/jonboulle/clockwork v0.5.0/go.mod h1:3mZlmanh0g2NDKO5TWZVJAfofYk64M7XN3SzBPjZF60= github.com/mattermost/xml-roundtrip-validator v0.1.0 h1:RXbVD2UAl7A7nOTR4u7E3ILa4IbtvKBHw64LDsmu9hU= @@ -33,8 +25,6 @@ github.com/mdlayher/netlink v1.8.0 h1:e7XNIYJKD7hUct3Px04RuIGJbBxy1/c4nX7D5Yyvvl github.com/mdlayher/netlink v1.8.0/go.mod h1:UhgKXUlDQhzb09DrCl2GuRNEglHmhYoWAHid9HK3594= github.com/mdlayher/socket v0.5.1 h1:VZaqt6RkGkt2OE9l3GcC6nZkqD3xKeQLyfleW/uBcos= github.com/mdlayher/socket v0.5.1/go.mod h1:TjPLHI1UgwEv5J1B5q0zTZq12A/6H7nKmtTanQE37IQ= -github.com/packetcap/go-pcap v0.0.0-20251012111502-b21daddd9e00 h1:mZeo53cf/lsCL4kj8QkmgXSRDK1caYmVI1aCq3Wi62o= -github.com/packetcap/go-pcap v0.0.0-20251012111502-b21daddd9e00/go.mod h1:1jryUz9E2ndKwZBNHzVhLMzS3WHO0fOKydYi9XWWu9w= github.com/packetcap/go-pcap v0.0.0-20251215121130-f2cf9f991e7c h1:B5gWB1LB6OxpoXz+FsLUhQEcCAtMpajhBZ2K0X9KjfE= github.com/packetcap/go-pcap v0.0.0-20251215121130-f2cf9f991e7c/go.mod h1:1jryUz9E2ndKwZBNHzVhLMzS3WHO0fOKydYi9XWWu9w= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= @@ -43,38 +33,22 @@ github.com/russellhaering/gosaml2 v0.10.0 h1:z7JTpKmC4JVG94tvSQz4lszUdKLt+uy5c6l github.com/russellhaering/gosaml2 v0.10.0/go.mod h1:XLwI/5aWV4E2X9p+qj6LgRwiYGv2nh4YS6pQBGlQ0Cc= github.com/russellhaering/goxmldsig v1.5.0 h1:AU2UkkYIUOTyZRbe08XMThaOCelArgvNfYapcmSjBNw= github.com/russellhaering/goxmldsig v1.5.0/go.mod h1:x98CjQNFJcWfMxeOrMnMKg70lvDP6tE0nTaeUnjXDmk= -github.com/sirupsen/logrus v1.9.3 h1:dueUQJ1C2q9oE3F7wvmSGAaVtTmUizReu6fjN8uqzbQ= -github.com/sirupsen/logrus v1.9.3/go.mod h1:naHLuLoDiP4jHNo9R0sCBMtWGeIprob74mVsIT4qYEQ= github.com/sirupsen/logrus v1.9.4 h1:TsZE7l11zFCLZnZ+teH4Umoq5BhEIfIzfRDZ1Uzql2w= github.com/sirupsen/logrus v1.9.4/go.mod h1:ftWc9WdOfJ0a92nsE2jF5u5ZwH8Bv2zdeOC42RjbV2g= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= -github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.10.0 h1:Xv5erBjTwe/5IxqUQTdXv5kgmIvbHo3QQyRwhJsOfJA= github.com/stretchr/testify v1.10.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY= -golang.org/x/crypto v0.45.0 h1:jMBrvKuj23MTlT0bQEOBcAE0mjg8mK9RXFhRH6nyF3Q= -golang.org/x/crypto v0.45.0/go.mod h1:XTGrrkGJve7CYK7J8PEww4aY7gM3qMCElcJQ8n8JdX4= golang.org/x/crypto v0.48.0 h1:/VRzVqiRSggnhY7gNRxPauEQ5Drw9haKdM0jqfcCFts= golang.org/x/crypto v0.48.0/go.mod h1:r0kV5h3qnFPlQnBSrULhlsRfryS2pmewsg+XfMgkVos= -golang.org/x/net v0.47.0 h1:Mx+4dIFzqraBXUugkia1OOvlD6LemFo1ALMHjrXDOhY= -golang.org/x/net v0.47.0/go.mod h1:/jNxtkgq5yWUGYkaZGqo27cfGZ1c5Nen03aYrrKpVRU= golang.org/x/net v0.50.0 h1:ucWh9eiCGyDR3vtzso0WMQinm2Dnt8cFMuQa9K33J60= golang.org/x/net v0.50.0/go.mod h1:UgoSli3F/pBgdJBHCTc+tp3gmrU4XswgGRgtnwWTfyM= -golang.org/x/sync v0.18.0 h1:kr88TuHDroi+UVf+0hZnirlk8o8T+4MrK6mr60WkH/I= -golang.org/x/sync v0.18.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= golang.org/x/sync v0.19.0 h1:vV+1eWNmZ5geRlYjzm2adRgW2/mcpevXNg50YZtPCE4= golang.org/x/sync v0.19.0/go.mod h1:9KTHXmSnoGruLpwFjVSX0lNNA75CykiMECbovNTZqGI= -golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.38.0 h1:3yZWxaJjBmCWXqhN1qh02AkOnCQ1poK6oF+a7xWL6Gc= -golang.org/x/sys v0.38.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= golang.org/x/sys v0.41.0 h1:Ivj+2Cp/ylzLiEU89QhWblYnOE9zerudt9Ftecq2C6k= golang.org/x/sys v0.41.0/go.mod h1:OgkHotnGiDImocRcuBABYBEXf8A9a87e/uXjp9XT3ks= -golang.org/x/term v0.37.0 h1:8EGAD0qCmHYZg6J17DvsMy9/wJ7/D/4pV/wfnld5lTU= -golang.org/x/term v0.37.0/go.mod h1:5pB4lxRNYYVZuTLmy8oR2BH8dflOR+IbTYFD8fi3254= golang.org/x/term v0.40.0 h1:36e4zGLqU4yhjlmxEaagx2KuYbJq3EwY8K943ZsHcvg= golang.org/x/term v0.40.0/go.mod h1:w2P8uVp06p2iyKKuvXIm7N/y0UCRt3UfJTfZ7oOpglM= -golang.org/x/text v0.31.0 h1:aC8ghyu4JhP8VojJ2lEHBnochRno1sgL6nEi9WGFGMM= -golang.org/x/text v0.31.0/go.mod h1:tKRAlv61yKIjGGHX/4tP1LTbc13YSec1pxVEWXzfoeM= golang.org/x/text v0.34.0 h1:oL/Qq0Kdaqxa1KbNeMKwQq0reLCCaFtqu2eNuSeNHbk= golang.org/x/text v0.34.0/go.mod h1:homfLqTYRFyVYemLBFl5GgL/DWEiH5wcsQ5gSh1yziA= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/latest b/latest index 6a99dbb..95ff739 100644 --- a/latest +++ b/latest @@ -1 +1 @@ -v1.1.14 +v1.1.15 diff --git a/webapp/src/Auth/AuthBanner.tsx b/webapp/src/Auth/AuthBanner.tsx index 54d3d21..ff4f330 100644 --- a/webapp/src/Auth/AuthBanner.tsx +++ b/webapp/src/Auth/AuthBanner.tsx @@ -1,16 +1,16 @@ -import {useState} from 'react'; +import { useState } from 'react'; import { - TextInput, - PasswordInput, - Paper, - Title, - Container, - Button, - Group, - Divider, - Text, - Alert, - } from '@mantine/core'; + TextInput, + PasswordInput, + Paper, + Title, + Container, + Button, + Group, + Divider, + Text, + Alert, +} from '@mantine/core'; import classes from './AuthBanner.module.css'; import { useMutation, useQuery } from '@tanstack/react-query'; import axios from 'axios'; @@ -51,119 +51,99 @@ type LoginPassword = { export function AuthBanner() { - const [login, setLogin] = useState(""); - const [password, setPassword] = useState(""); - const [authError, setAuthError] = useState(""); - const {authInfo, setAuthInfo} = useAuthContext(); - const [oidcRedirectError, setOidcRedirectError] = useState("") - const [showMFAFactors, setShowMFAFactors] = useState>([]) - const [factorResponse, setFactorResponse] = useState({name: "", code: ""}) - const { error, isPending, data } = useQuery({ - queryKey: ['authmethods'], - queryFn: () => - fetch(AppSettings.url + '/authmethods') + const [login, setLogin] = useState(""); + const [password, setPassword] = useState(""); + const [authError, setAuthError] = useState(""); + const { authInfo, setAuthInfo } = useAuthContext(); + const [showMFAFactors, setShowMFAFactors] = useState>([]) + const [factorResponse, setFactorResponse] = useState({ name: "", code: "" }) + const { error, isPending, data } = useQuery({ + queryKey: ['authmethods'], + queryFn: () => + fetch(AppSettings.url + '/authmethods') .then((res) => res.json(), ) - }) - - const authenticate = useMutation({ - mutationFn: (loginPassword:LoginPassword) => { - setAuthError("") - return axios.post(AppSettings.url + '/auth', loginPassword) - }, - onSuccess: (response) => { - const data = response.data as LoginResponse - if(data.mfaRequired) { - setShowMFAFactors(data.factors) - } else { - setAuthInfo({...authInfo, token: data.token}) - } - }, - onError: (error) => { - if(error.message.includes("status code 401")) { - setAuthError("Invalid credentials") - } else if(error.message.includes("status code 429")) { - setAuthError("too many attempts. Try again later") - } else { - setAuthError("Error: "+ error.message) - } - } - }) - const oidcRedirect = useMutation({ - mutationFn: (id:string) => { - return axios.get(AppSettings.url + '/authmethods/oidc/' + id) - }, - onSuccess: (response) => { - const data = response.data as OIDCProvider - const redirectURI = data.redirectURI || "" - if(redirectURI === "") { - setOidcRedirectError("Could not redirect at this time: redirectURI is empty") - } else { - window.location.href = redirectURI - } - - }, - onError: (error) => { - setOidcRedirectError("Could not redirect at this time: "+ error.message) - } - }) - const onClickOidcRedirect = (id:string) => { - oidcRedirect.mutate(id) - } + }) - const captureEnter = (e: React.KeyboardEvent) => { - if (e.key === "Enter") { - authenticate.mutate({login, password, factorResponse}) + const authenticate = useMutation({ + mutationFn: (loginPassword: LoginPassword) => { + setAuthError("") + return axios.post(AppSettings.url + '/auth', loginPassword) + }, + onSuccess: (response) => { + const data = response.data as LoginResponse + if (data.mfaRequired) { + setShowMFAFactors(data.factors) + } else { + setAuthInfo({ ...authInfo, token: data.token }) } + }, + onError: (error) => { + if (error.message.includes("status code 401")) { + setAuthError("Invalid credentials") + } else if (error.message.includes("status code 429")) { + setAuthError("too many attempts. Try again later") + } else { + setAuthError("Error: " + error.message) + } + } + }) + const onClickOidcRedirect = (id: string) => { + window.location.href = AppSettings.url + '/authmethods/oidc/' + id + "/redirect" + } + + const captureEnter = (e: React.KeyboardEvent) => { + if (e.key === "Enter") { + authenticate.mutate({ login, password, factorResponse }) } - const alertIcon = - - if (error) return 'An backend error has occurred: ' + error.message + } + const alertIcon = - const authMethodsButtons = data?.oidcProviders.map((oidcProvider:OIDCProvider) => ( - - )) + if (error) return 'An backend error has occurred: ' + error.message - return ( - - - VPN Server - - - - - {oidcRedirectError === "" ? "" :

oidcRedirectError

} - {authMethodsButtons} -
- {isPending || data?.localAuthDisabled ? null : + const authMethodsButtons = data?.oidcProviders.map((oidcProvider: OIDCProvider) => ( + + )) + + return ( + + + VPN Server + + + + + {authMethodsButtons} + + {isPending || data?.localAuthDisabled ? null : + <> + {data?.oidcProviders === undefined || data?.oidcProviders.length < 1 ? null : + + } + {authError !== "" ? + {authError} + : + null + } + {showMFAFactors.length > 0 ? + + : <> - {data?.oidcProviders === undefined || data?.oidcProviders.length < 1 ? null : - - } - {authError !== "" ? - {authError} - : - null - } - {showMFAFactors.length > 0 ? - - : - <> - setLogin(event.currentTarget.value)} value={login} onKeyDown={(e) => captureEnter(e)} /> - setPassword(event.currentTarget.value)} value={password} onKeyDown={(e) => captureEnter(e)} /> - - } - - By clicking 'Sign in', you accept the Terms & Conditions + setLogin(event.currentTarget.value)} value={login} onKeyDown={(e) => captureEnter(e)} /> + setPassword(event.currentTarget.value)} value={password} onKeyDown={(e) => captureEnter(e)} /> } + + By clicking 'Sign in', you accept the Terms & Conditions + + } + + + + ); -
-
- ); - } \ No newline at end of file diff --git a/webapp/src/Auth/OIDCAndSAMLRedirect.tsx b/webapp/src/Auth/OIDCAndSAMLRedirect.tsx index 7fddd66..2d7b9d4 100644 --- a/webapp/src/Auth/OIDCAndSAMLRedirect.tsx +++ b/webapp/src/Auth/OIDCAndSAMLRedirect.tsx @@ -1,41 +1,14 @@ -import { useEffect, useState } from "react"; +import { useEffect } from "react"; import { AppSettings } from "../Constants/Constants"; -import axios from "axios"; -import { useMutation } from "@tanstack/react-query"; import { useMatch } from "react-router-dom"; -type AuthParams = { - loginType: string; - loginID: string; - }; - export function OIDCAndSAMLRedirect() { - const [redirectError, setRedirectError] = useState("") - const loginMatch = useMatch("/login/:loginType/:loginID"); - const redirect = useMutation({ - mutationFn: (authParams:AuthParams) => { - return axios.get(AppSettings.url + '/authmethods/'+authParams.loginType+'/' + authParams.loginID) - }, - onSuccess: (response) => { - const data = response.data as OIDCProvider - const redirectURI = data.redirectURI || "" - if(redirectURI === "") { - setRedirectError("Could not redirect at this time: redirectURI is empty") - } else { - window.location.href = redirectURI - } - - }, - onError: (error) => { - setRedirectError("Could not redirect at this time: "+ error.message) - } - }) + const loginMatch = useMatch("/login/:loginType/:loginID"); - useEffect(() => { - if(loginMatch && loginMatch.params.loginType !== undefined && loginMatch.params.loginID !== undefined) { - redirect.mutate({loginType:loginMatch.params.loginType, loginID: loginMatch.params.loginID}) - } - }, []); - if(redirectError !== "") return

RedirectError

- return (<>) + useEffect(() => { + if (loginMatch && loginMatch.params.loginType !== undefined && loginMatch.params.loginID !== undefined) { + window.location.href = AppSettings.url + '/authmethods/' + loginMatch.params.loginType + '/' + loginMatch.params.loginID + "/redirect" + } + }, []); + return (<>) } \ No newline at end of file