Initial QSfera import
This commit is contained in:
+146
@@ -0,0 +1,146 @@
|
||||
/*
|
||||
* 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
|
||||
}
|
||||
Reference in New Issue
Block a user