login-sim/server.go

98 lines
2.4 KiB
Go
Raw Normal View History

2022-12-02 14:31:43 +08:00
/*
* Copyright IDMesh Authors
*
* 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 main
import (
"errors"
"fmt"
"log"
"net/http"
)
const (
CookieKeyIDMeshUserID = "IDMesh-User-Id"
)
type Config struct {
// MUST, default redirect url
DefaultRedirectURL string `json:"default_redirect_url"`
// OPTIONAL, map[user_id]redirect_url, fallback: default_redirect_url
Rules map[string]string `json:"rules"`
}
func (cfg *Config) Validate() error {
if cfg.DefaultRedirectURL == "" {
return errors.New("empty `default_redirect_url`")
}
return nil
}
type RelayServer struct {
cfg *Config
}
func NewRelayServer(cfg Config) (http.Handler, error) {
if err := cfg.Validate(); err != nil {
return nil, err
}
return &RelayServer{cfg: &cfg}, nil
}
func (s *RelayServer) ServeHTTP(w http.ResponseWriter, r *http.Request) {
switch r.URL.Path {
case "", "/":
uid, err := s.readUserID(r)
if err != nil {
log.Println(err)
s.redirect(w, s.cfg.DefaultRedirectURL)
return
}
loc, ok := s.cfg.Rules[uid]
if !ok {
log.Println("unexpected uid:", uid, ", fallback to default url:", s.cfg.DefaultRedirectURL)
s.redirect(w, s.cfg.DefaultRedirectURL)
return
}
s.redirect(w, loc)
default:
w.WriteHeader(http.StatusNotFound)
}
}
func (s *RelayServer) redirect(w http.ResponseWriter, loc string) {
nr, err := http.NewRequest(http.MethodGet, loc, nil)
if err != nil {
log.Printf("fail to make request: %v", err)
w.WriteHeader(http.StatusInternalServerError)
w.Write([]byte("internal error"))
return
}
http.Redirect(w, nr, loc, http.StatusFound)
}
func (s *RelayServer) readUserID(r *http.Request) (string, error) {
c, err := r.Cookie(CookieKeyIDMeshUserID)
if err != nil {
if errors.Is(err, http.ErrNoCookie) {
return "", fmt.Errorf("read user: cookie %q not found", CookieKeyIDMeshUserID)
}
return "", fmt.Errorf("read user: fail to read cookie: %v", err)
}
return c.Value, nil
}