mirror of
https://github.com/opencloud-eu/opencloud.git
synced 2025-12-30 09:38:26 -05:00
147 lines
4.2 KiB
Go
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
|
|
}
|