Files
Christian Richter 96d83dbcd9 bump to changes in upstream PR
Signed-off-by: Christian Richter <c.richter@opencloud.eu>
2025-04-28 13:36:13 +02:00

147 lines
4.2 KiB
Go

/*
* Copyright 2017-2019 Kopano and its licensors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package identifier
import (
"bytes"
"fmt"
"net/http"
"github.com/libregraph/oidc-go"
"github.com/longsleep/rndm"
"github.com/libregraph/lico/identifier/meta"
"github.com/libregraph/lico/identifier/meta/scopes"
)
func (i *Identifier) writeWebappIndexHTML(rw http.ResponseWriter, req *http.Request) {
nonce := rndm.GenerateRandomString(32)
// FIXME(longsleep): Set a secure CSP. Right now we need `data:` for images
// since it is used. Since `data:` URLs possibly could allow xss, a better
// way should be found for our early loading inline SVG stuff.
rw.Header().Set("Content-Security-Policy", fmt.Sprintf("default-src 'self'; img-src 'self' data:; font-src 'self' data:; script-src 'self' 'nonce-%s'; style-src 'self' 'nonce-%s'; base-uri 'none'; frame-ancestors 'none';", nonce, nonce))
// Write index with random nonce to response.
index := bytes.ReplaceAll(i.webappIndexHTML, []byte("__CSP_NONCE__"), []byte(nonce))
rw.Write(index)
}
func (i Identifier) writeHelloResponse(rw http.ResponseWriter, req *http.Request, r *HelloRequest, identifiedUser *IdentifiedUser) (*HelloResponse, error) {
var err error
response := &HelloResponse{
State: r.State,
Branding: &meta.Branding{
BannerLogo: i.defaultBannerLogo,
UsernameHintText: i.Config.DefaultUsernameHintText,
SignInPageText: i.Config.DefaultSignInPageText,
SignInPageLogoURI: i.Config.DefaultSignInPageLogoURI,
Locales: i.Config.UILocales,
},
}
handleHelloLoop:
for {
// Check prompt value.
switch {
case r.Prompts[oidc.PromptNone] == true:
// Never show sign-in, directly return error.
return nil, fmt.Errorf("prompt none requested")
case r.Prompts[oidc.PromptLogin] == true:
// Ignore all potential sources, when prompt login was requested.
if identifiedUser != nil {
response.Username = identifiedUser.Username()
response.DisplayName = identifiedUser.Name()
if response.Username != "" {
response.Success = true
}
}
break handleHelloLoop
default:
// Let all other prompt values pass.
}
if identifiedUser == nil {
// Check if logged in via cookie.
identifiedUser, err = i.GetUserFromLogonCookie(req.Context(), req, r.MaxAge, true)
if err != nil {
i.logger.WithError(err).Debugln("identifier failed to decode logon cookie in hello")
}
}
if identifiedUser != nil {
response.Username = identifiedUser.Username()
response.DisplayName = identifiedUser.Name()
if response.Username != "" {
response.Success = true
break
}
}
break
}
if !response.Success {
return response, nil
}
switch r.Flow {
case FlowOAuth:
fallthrough
case FlowConsent:
fallthrough
case FlowOIDC:
// TODO(longsleep): Add something to validate the parameters.
clientDetails, err := i.clients.Lookup(req.Context(), r.ClientID, "", r.RedirectURI, "", true)
if err != nil {
return nil, err
}
promptConsent := false
// Check prompt value.
switch {
case r.Prompts[oidc.PromptConsent] == true:
promptConsent = true
default:
// Let all other prompt values pass.
}
// If not trusted, always force consent.
if !clientDetails.Trusted {
promptConsent = true
}
if promptConsent {
// TODO(longsleep): Filter scopes to scopes we know about and all.
response.Next = FlowConsent
response.Scopes = r.Scopes
response.ClientDetails = clientDetails
response.Meta = &meta.Meta{
Scopes: scopes.NewScopesFromIDs(r.Scopes, i.meta.Scopes),
}
}
// Add authorize endpoint URI as continue URI.
response.ContinueURI = i.authorizationEndpointURI.String()
response.Flow = r.Flow
}
return response, nil
}