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 {
type Config struct {
BaseURL string `yaml:"base_url"`
UsersFile string `yaml:"users_file"`
UsersFile string `yaml:"users_file"`
EmailUsernames bool `yaml:"email_usernames"`
// SAML X509 credentials.
CertificateFile string `yaml:"certificate_file"`
......@@ -134,25 +135,63 @@ type userInfo struct {
Email string `yaml:"email"`
}
type userBackend interface {
GetUser(string) (*userInfo, bool)
}
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) {
data, err := ioutil.ReadFile(config.UsersFile)
func newUserFileBackend(path string) (*userFileBackend, error) {
data, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
var userList []userInfo
var userList []*userInfo
if err := yaml.Unmarshal(data, &userList); err != nil {
return nil, err
}
users := make(map[string]userInfo)
users := make(map[string]*userInfo)
for _, u := range userList {
users[u.Name] = u
}
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,
users: users,
}, nil
......@@ -173,7 +212,7 @@ func matchGroups(user, exp []string) bool {
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
// also need to be able to retrieve user information from the
// 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
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)
return nil
}
user, ok := b.users[username]
user, ok := sp.users.GetUser(username)
if !ok {
log.Printf("error: user %s is authenticated but unknown", username)
http.Error(w, "User not found", http.StatusInternalServerError)
......@@ -252,7 +291,7 @@ func NewSAMLIDP(config *Config) (http.Handler, error) {
svc += "/"
}
users, err := newUserFileBackend(config)
sp, err := newSessionProvider(config)
if err != nil {
return nil, err
}
......@@ -267,7 +306,7 @@ func NewSAMLIDP(config *Config) (http.Handler, error) {
MetadataURL: metadataURL,
SSOURL: ssoURL,
ServiceProviderProvider: config,
SessionProvider: users,
SessionProvider: sp,
}
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