Skip to content
Snippets Groups Projects
Commit d00e7f54 authored by ale's avatar ale
Browse files

Support the case where usernames are already email addresses

In this scenario there is no need to set 'users_file', instead we
introduce the new boolean attribute 'email_usernames'.
parent f1c2d0bf
No related branches found
No related tags found
No related merge requests found
...@@ -41,7 +41,8 @@ type serviceProvider struct { ...@@ -41,7 +41,8 @@ type serviceProvider struct {
type Config struct { type Config struct {
BaseURL string `yaml:"base_url"` BaseURL string `yaml:"base_url"`
UsersFile string `yaml:"users_file"` UsersFile string `yaml:"users_file"`
EmailUsernames bool `yaml:"email_usernames"`
// SAML X509 credentials. // SAML X509 credentials.
CertificateFile string `yaml:"certificate_file"` CertificateFile string `yaml:"certificate_file"`
...@@ -134,25 +135,63 @@ type userInfo struct { ...@@ -134,25 +135,63 @@ type userInfo struct {
Email string `yaml:"email"` Email string `yaml:"email"`
} }
type userBackend interface {
GetUser(string) (*userInfo, bool)
}
type userFileBackend struct { type userFileBackend struct {
config *Config users map[string]*userInfo
users map[string]userInfo }
func (b *userFileBackend) GetUser(username string) (*userInfo, bool) {
info, ok := b.users[username]
return info, ok
} }
func newUserFileBackend(config *Config) (*userFileBackend, error) { func newUserFileBackend(path string) (*userFileBackend, error) {
data, err := ioutil.ReadFile(config.UsersFile) data, err := ioutil.ReadFile(path)
if err != nil { if err != nil {
return nil, err return nil, err
} }
var userList []userInfo var userList []*userInfo
if err := yaml.Unmarshal(data, &userList); err != nil { if err := yaml.Unmarshal(data, &userList); err != nil {
return nil, err return nil, err
} }
users := make(map[string]userInfo) users := make(map[string]*userInfo)
for _, u := range userList { for _, u := range userList {
users[u.Name] = u users[u.Name] = u
} }
return &userFileBackend{ return &userFileBackend{
users: users,
}, nil
}
type identityUserBackend struct{}
func (b *identityUserBackend) GetUser(username string) (*userInfo, bool) {
return &userInfo{Name: username, Email: username}, true
}
type sessionProvider struct {
config *Config
users userBackend
}
func newSessionProvider(config *Config) (*sessionProvider, error) {
var users userBackend
var err error
switch {
case config.UsersFile != "":
users, err = newUserFileBackend(config.UsersFile)
if err != nil {
return nil, err
}
case config.EmailUsernames:
users = new(identityUserBackend)
default:
return nil, errors.New("neither users_file or email_usernames are specified")
}
return &sessionProvider{
config: config, config: config,
users: users, users: users,
}, nil }, nil
...@@ -173,7 +212,7 @@ func matchGroups(user, exp []string) bool { ...@@ -173,7 +212,7 @@ func matchGroups(user, exp []string) bool {
return false return false
} }
func (b *userFileBackend) GetSession(w http.ResponseWriter, r *http.Request, req *saml.IdpAuthnRequest) *saml.Session { func (sp *sessionProvider) GetSession(w http.ResponseWriter, r *http.Request, req *saml.IdpAuthnRequest) *saml.Session {
// Check for authentication by verifying the SSO username. We // Check for authentication by verifying the SSO username. We
// also need to be able to retrieve user information from the // also need to be able to retrieve user information from the
// backend, to match SSO. Group membership, if enabled in our // backend, to match SSO. Group membership, if enabled in our
...@@ -185,12 +224,12 @@ func (b *userFileBackend) GetSession(w http.ResponseWriter, r *http.Request, req ...@@ -185,12 +224,12 @@ func (b *userFileBackend) GetSession(w http.ResponseWriter, r *http.Request, req
return nil return nil
} }
if !matchGroups(httpsso.Groups(r), b.config.GetSSOGroups(req.ServiceProviderMetadata.ID)) { if !matchGroups(httpsso.Groups(r), sp.config.GetSSOGroups(req.ServiceProviderMetadata.ID)) {
http.Error(w, "Forbidden (bad group)", http.StatusForbidden) http.Error(w, "Forbidden (bad group)", http.StatusForbidden)
return nil return nil
} }
user, ok := b.users[username] user, ok := sp.users.GetUser(username)
if !ok { if !ok {
log.Printf("error: user %s is authenticated but unknown", username) log.Printf("error: user %s is authenticated but unknown", username)
http.Error(w, "User not found", http.StatusInternalServerError) http.Error(w, "User not found", http.StatusInternalServerError)
...@@ -252,7 +291,7 @@ func NewSAMLIDP(config *Config) (http.Handler, error) { ...@@ -252,7 +291,7 @@ func NewSAMLIDP(config *Config) (http.Handler, error) {
svc += "/" svc += "/"
} }
users, err := newUserFileBackend(config) sp, err := newSessionProvider(config)
if err != nil { if err != nil {
return nil, err return nil, err
} }
...@@ -267,7 +306,7 @@ func NewSAMLIDP(config *Config) (http.Handler, error) { ...@@ -267,7 +306,7 @@ func NewSAMLIDP(config *Config) (http.Handler, error) {
MetadataURL: metadataURL, MetadataURL: metadataURL,
SSOURL: ssoURL, SSOURL: ssoURL,
ServiceProviderProvider: config, ServiceProviderProvider: config,
SessionProvider: users, SessionProvider: sp,
} }
h := idp.Handler() h := idp.Handler()
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment