mirror of
https://github.com/hay-kot/homebox.git
synced 2025-08-03 08:10:28 +00:00
proof of concept login mechanism using trusted SSO headers as described here:
https://www.authelia.com/integration/trusted-header-sso/introduction/
This commit is contained in:
parent
d3b6c93b63
commit
df6a375030
5 changed files with 56 additions and 0 deletions
|
@ -89,6 +89,28 @@ func (ctrl *V1Controller) HandleAuthLogin() errchain.HandlerFunc {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (ctrl *V1Controller) HandleSsoHeaderLogin() server.HandlerFunc {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request) error {
|
||||||
|
var username = r.Header.Get("Remote-Email")
|
||||||
|
|
||||||
|
if username == "" {
|
||||||
|
return validate.NewRequestError(errors.New("authentication failed. not SSO header found"), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
newToken, err := ctrl.svc.User.LoginWithoutPassword(r.Context(), strings.ToLower(username))
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
return validate.NewRequestError(errors.New("authentication failed"), http.StatusInternalServerError)
|
||||||
|
}
|
||||||
|
|
||||||
|
return server.Respond(w, http.StatusOK, TokenResponse{
|
||||||
|
Token: "Bearer " + newToken.Raw,
|
||||||
|
ExpiresAt: newToken.ExpiresAt,
|
||||||
|
AttachmentToken: newToken.AttachmentToken,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// HandleAuthLogout godoc
|
// HandleAuthLogout godoc
|
||||||
//
|
//
|
||||||
// @Summary User Logout
|
// @Summary User Logout
|
||||||
|
|
|
@ -64,6 +64,7 @@ func (a *app) mountRoutes(r *chi.Mux, chain *errchain.ErrChain, repos *repo.AllR
|
||||||
|
|
||||||
r.Post(v1Base("/users/register"), chain.ToHandlerFunc(v1Ctrl.HandleUserRegistration()))
|
r.Post(v1Base("/users/register"), chain.ToHandlerFunc(v1Ctrl.HandleUserRegistration()))
|
||||||
r.Post(v1Base("/users/login"), chain.ToHandlerFunc(v1Ctrl.HandleAuthLogin()))
|
r.Post(v1Base("/users/login"), chain.ToHandlerFunc(v1Ctrl.HandleAuthLogin()))
|
||||||
|
r.server.Post(v1Base("/users/login-sso-header"), v1Ctrl.HandleSsoHeaderLogin())
|
||||||
|
|
||||||
userMW := []errchain.Middleware{
|
userMW := []errchain.Middleware{
|
||||||
a.mwAuthToken,
|
a.mwAuthToken,
|
||||||
|
|
|
@ -193,6 +193,18 @@ func (svc *UserService) Login(ctx context.Context, username, password string, ex
|
||||||
return svc.createSessionToken(ctx, usr.ID, extendedSession)
|
return svc.createSessionToken(ctx, usr.ID, extendedSession)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (svc *UserService) LoginWithoutPassword(ctx context.Context, username string) (UserAuthTokenDetail, error) {
|
||||||
|
usr, err := svc.repos.Users.GetOneEmail(ctx, username)
|
||||||
|
|
||||||
|
if err != nil {
|
||||||
|
// SECURITY: Perform hash to ensure response times are the same
|
||||||
|
hasher.CheckPasswordHash("not-a-real-password", "not-a-real-password")
|
||||||
|
return UserAuthTokenDetail{}, ErrorInvalidLogin
|
||||||
|
}
|
||||||
|
|
||||||
|
return svc.createSessionToken(ctx, usr.ID)
|
||||||
|
}
|
||||||
|
|
||||||
func (svc *UserService) Logout(ctx context.Context, token string) error {
|
func (svc *UserService) Logout(ctx context.Context, token string) error {
|
||||||
hash := hasher.HashToken(token)
|
hash := hasher.HashToken(token)
|
||||||
err := svc.repos.AuthTokens.DeleteToken(ctx, hash)
|
err := svc.repos.AuthTokens.DeleteToken(ctx, hash)
|
||||||
|
|
|
@ -24,6 +24,14 @@ export class PublicApi extends BaseAPI {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public login_sso_header() {
|
||||||
|
return this.http.post<string, TokenResponse>({
|
||||||
|
url: route("/users/login-sso-header"),
|
||||||
|
/** TODO: remove header here. Only for testing. Usually the SSO servie will add this */
|
||||||
|
headers: { "Remote-Email": "demo@example.com" },
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
public register(body: UserRegistration) {
|
public register(body: UserRegistration) {
|
||||||
return this.http.post<UserRegistration, TokenResponse>({ url: route("/users/register"), body });
|
return this.http.post<UserRegistration, TokenResponse>({ url: route("/users/register"), body });
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,6 +32,19 @@
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const { data, error } = await api.login_sso_header();
|
||||||
|
|
||||||
|
if (!error) {
|
||||||
|
// @ts-expect-error - expires is either a date or a string, need to figure out store typing
|
||||||
|
authStore.$patch({
|
||||||
|
token: data.token,
|
||||||
|
expires: data.expiresAt,
|
||||||
|
attachmentToken: data.attachmentToken,
|
||||||
|
});
|
||||||
|
|
||||||
|
navigateTo("/home");
|
||||||
|
}
|
||||||
|
|
||||||
const route = useRoute();
|
const route = useRoute();
|
||||||
const router = useRouter();
|
const router = useRouter();
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue