added auth arg validation and set up auth package

This commit is contained in:
Souhaila Noor 2021-12-02 13:09:13 -06:00
parent dc1c39fd21
commit b5ba3fb2ea
7 changed files with 189 additions and 59 deletions

47
auth/auth.go Normal file
View file

@ -0,0 +1,47 @@
// Copyright 2017 Pilosa Corp.
//
// 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 auth
type AUTH struct {
ClientId string
ClientSecret string
AuthorizeURL string
TokenURL string
GroupEndpointURL string
}
// func (c *config) Init(ClientId, ClientSecret, AuthorizeURL, TokenURL, GroupEndpointURL string) {
// c.ClientId = ClientId
// c.ClientSecret = ClientSecret
// c.AuthorizeURL = AuthorizeURL
// c.TokenURL = TokenURL
// c.GroupEndpointURL = GroupEndpointURL
// }
// apiOption is a functional option type for pilosa.API
type authOption func(*AUTH) error
func OptAuth(ClientId, ClientSecret, AuthorizeURL, TokenURL, GroupEndpointURL string) authOption {
return func(a *AUTH) error {
a.ClientId = ClientId
a.ClientSecret = ClientSecret
a.AuthorizeURL = AuthorizeURL
a.TokenURL = TokenURL
a.GroupEndpointURL = GroupEndpointURL
return nil
}
}
// redirectURL

View file

@ -124,8 +124,10 @@ func BuildServerFlags(cmd *cobra.Command, srv *server.Command) {
// OAuth2.0 identity provider configuration
flags.BoolVar(&srv.Config.Auth.Enable, "auth.enable", false, "Enable AuthN/AuthZ of featurebase, disabled by default.")
flags.StringVar(&srv.Config.Auth.IdentityProviderURL, "auth.identity-provider-url", srv.Config.Auth.IdentityProviderURL, "Base URL for identity provider.")
flags.StringVar(&srv.Config.Auth.AuthorizeURL, "auth.authorize-url", srv.Config.Auth.AuthorizeURL, "Base URL for authorize.")
flags.StringVar(&srv.Config.Auth.UserInfoURL, "auth.user-info-url", srv.Config.Auth.UserInfoURL, "Base URL for user info.")
flags.StringVar(&srv.Config.Auth.ClientId, "auth.client-id", srv.Config.Auth.ClientId, "Application/Client ID")
flags.StringVar(&srv.Config.Auth.ClientId, "auth.client-id", srv.Config.Auth.ClientId, "Identity Provider's Application/Client ID.")
flags.StringVar(&srv.Config.Auth.ClientSecret, "auth.client-secret", srv.Config.Auth.ClientSecret, "Identity Provider's Application/Client Secret.")
flags.StringVar(&srv.Config.Auth.AuthorizeURL, "auth.authorize-url", srv.Config.Auth.AuthorizeURL, "Identity Provider's Authorize URL.")
flags.StringVar(&srv.Config.Auth.TokenURL, "auth.token-url", srv.Config.Auth.TokenURL, "Identity Provider's Token URL for identity provider.")
flags.StringVar(&srv.Config.Auth.GroupEndpointURL, "auth.group-endpoint-url", srv.Config.Auth.GroupEndpointURL, "Identity Provider's Group endpoint URL.")
}

View file

@ -375,7 +375,8 @@ log-path = "/var/log/molecula/featurebase.log"
# Can choose identity provider, pass authorize and user-info endpoints, and client id
# [auth]
# enable = false
# identity-provider-url = "http://place-holder"
# authorize-url = "http://place-holder"
# user-info-url = "http://place-holder"
# client-id = "http://place-holder"
# client-id = ""
# client-secret = ""
# authorize-url = ""
# token-url = ""
# group-endpoint-url = ""

View file

@ -1,35 +0,0 @@
// Copyright 2017 Pilosa Corp.
//
// 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 server
type Options struct {
Enable bool `toml:"enable"`
IdentityProviderURL string `toml:"identity-provider-url"`
AuthorizeURL string `toml:"authorize-url"`
UserInfoURL string `toml:"user-info-url"`
ClientId string `toml:"client-id"`
}
func authenticateUser(opt Options) (resp bool) {
// fmt.Println("IdentityProviderURL", opt.IdentityProviderURL)
// fmt.Println("AuthorizeURL", opt.AuthorizeURL)
// fmt.Println("UserInfoURL", opt.UserInfoURL)
// fmt.Println("ClientId", opt.ClientId)
resp = false
return resp
}

View file

@ -19,6 +19,7 @@ import (
"fmt"
"log"
"net"
"net/url"
"runtime"
"strconv"
"strings"
@ -246,17 +247,20 @@ type Config struct {
// Enable AuthZ/AuthN for featurebase server
Enable bool `toml:"enable"`
// Base URL for identity provider
IdentityProviderURL string `toml:"identity-provider-url"`
// Application/Client ID
ClientId string `toml:"client-id"`
// Client Secret
ClientSecret string `toml:"client-secret"`
// Authorize URL
AuthorizeURL string `toml:"authorize-url"`
// User info URL
UserInfoURL string `toml:"user-info-url"`
// Token URL
TokenURL string `toml:"token-url"`
// Application/Client ID
ClientId string `toml:"client-id"`
// Group Endpoint URL
GroupEndpointURL string `toml:"group-endpoint-url"`
} `toml:"auth"`
}
@ -291,6 +295,7 @@ func (c *Config) validate() error {
"Etcd.ClusterURL", c.Etcd.ClusterURL,
"Postgres.Bind", c.Postgres.Bind,
}
ports := make(map[int]bool)
n := len(hostPort)
for i := 0; i < n; i += 2 {
@ -411,12 +416,7 @@ func NewConfig() *Config {
c.SchemaDetailsOn = true
// AuthZ/AuthN disabled by default
// default identity provider is azure active directory
c.Auth.Enable = false
c.Auth.IdentityProviderURL = "http://holder-identity-provider"
c.Auth.AuthorizeURL = "http://holder-authorize-url"
c.Auth.UserInfoURL = "http://holder-user-info-url"
c.Auth.ClientId = "http://holder-client-id"
return c
}
@ -628,3 +628,37 @@ func lookupAddr(ctx context.Context, resolver *net.Resolver, host string) (strin
// No IPv4 address, return the first resolved address instead.
return addrs[0].String(), nil
}
func (c *Config) ValidateAuth() error {
authURL := []string{
"ClientId", c.Auth.ClientId,
"ClientSecret", c.Auth.ClientSecret,
"AuthorizeURL", c.Auth.AuthorizeURL,
"TokenURL", c.Auth.TokenURL,
"GroupEndpointURL", c.Auth.GroupEndpointURL,
}
n := len(authURL)
for i := 0; i < n; i += 2 {
name := authURL[i]
value := authURL[i+1]
if strings.Contains(name, "URL") {
_, err := url.ParseRequestURI(value)
if err != nil {
return fmt.Errorf("Invalid URL for auth config %s: %s", name, err)
}
} else {
if value == "" {
return fmt.Errorf("Empty string for auth config %s", name)
}
}
}
return nil
}
func (c *Config) MustValidateAuth() {
err := c.ValidateAuth()
if err != nil {
panic(err)
}
}

View file

@ -288,3 +288,86 @@ func TestConfig_validateAddrsGRPC(t *testing.T) {
})
}
}
type params struct {
enable bool
clientId string
clientSecret string
authorizeURL string
tokenURL string
groupEndpointURL string
}
func TestConfig_validateAuth(t *testing.T) {
tests := []struct {
expErr string
input params
expected params
}{
{"Empty string for auth config ClientId",
params{true, "", "", "", "", ""},
params{true, "clientidstring", "clientSecret", "https://url.com/", "https://url.com/", "https://url.com/"},
},
{"Empty string for auth config ClientSecret",
params{true, "clientid", "", "", "", ""},
params{true, "clientidstring", "clientSecret", "https://url.com/", "https://url.com/", "https://url.com/"},
},
{"Empty string for auth config ClientId",
params{true, "", "clientSecret", "", "", ""},
params{true, "clientidstring", "clientSecret", "https://url.com/", "https://url.com/", "https://url.com/"},
},
{"Invalid URL for auth config AuthorizeURL",
params{true, "client", "secret", "", "", ""},
params{true, "clientidstring", "clientSecret", "https://url.com/", "https://url.com/", "https://url.com/"},
},
{"Invalid URL for auth config TokenURL",
params{true, "client", "secret", "https://url.com/", "", ""},
params{true, "clientidstring", "clientSecret", "https://url.com/", "https://url.com/", "https://url.com/"},
},
{"Invalid URL for auth config GroupEndpointURL",
params{true, "client", "secret", "https://url.com/", "https://url.com/", ""},
params{true, "clientidstring", "clientSecret", "https://url.com/", "https://url.com/", "https://url.com/"},
},
{"Invalid URL for auth config AuthorizeURL",
params{true, "client", "secret", "string", "https://url.com/", "https://url.com/"},
params{true, "clientidstring", "clientSecret", "https://url.com/", "https://url.com/", "https://url.com/"},
},
{"Invalid URL for auth config TokenURL",
params{true, "client", "secret", "https://url.com/", "not-a-url", ""},
params{true, "clientidstring", "clientSecret", "https://url.com/", "https://url.com/", "https://url.com/"},
},
{"Invalid URL for auth config GroupEndpointURL",
params{true, "client", "secret", "https://url.com/", "https://url.com/", "not-valid-url"},
params{true, "clientidstring", "clientSecret", "https://url.com/", "https://url.com/", "https://url.com/"},
},
{"",
params{true, "client", "secret", "https://url.com/", "https://url.com/", "https://url.com/"},
params{true, "clientidstring", "clientSecret", "https://url.com/", "https://url.com/", "https://url.com/"},
},
}
for i, test := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
c := NewConfig()
c.Auth.Enable = test.input.enable
c.Auth.ClientId = test.input.clientId
c.Auth.ClientSecret = test.input.clientSecret
c.Auth.AuthorizeURL = test.input.authorizeURL
c.Auth.TokenURL = test.input.tokenURL
c.Auth.GroupEndpointURL = test.input.groupEndpointURL
err := c.ValidateAuth()
if err != nil && test.expErr == "" {
t.Fatal(err)
} else if err == nil && test.expErr != "" {
t.Fatalf("expected error string to contain %s, but got no error", test.expErr)
} else if err != nil && test.expErr != "" {
if !strings.Contains(err.Error(), test.expErr) {
t.Fatalf("expected error string to contain %s, but got %s", test.expErr, err.Error())
}
return
}
})
}
}

View file

@ -41,6 +41,7 @@ import (
"golang.org/x/sync/errgroup"
pilosa "github.com/molecula/featurebase/v2"
"github.com/molecula/featurebase/v2/auth"
"github.com/molecula/featurebase/v2/boltdb"
"github.com/molecula/featurebase/v2/encoding/proto"
petcd "github.com/molecula/featurebase/v2/etcd"
@ -235,11 +236,8 @@ func (m *Command) Start() (err error) {
}
if m.Config.Auth.Enable == true {
// check authentication for user
resp := authenticateUser(m.Config.Auth)
if resp == false {
log.Fatalf("Authentication failed: Unable to access to featurebase server")
}
m.Config.MustValidateAuth()
auth.OptAuth(m.Config.Auth.ClientId, m.Config.Auth.ClientSecret, m.Config.Auth.AuthorizeURL, m.Config.Auth.TokenURL, m.Config.Auth.GroupEndpointURL)
}
// Initialize server.