diff --git a/Dockerfile b/Dockerfile index dbc0dd38..d6ce6a9c 100644 --- a/Dockerfile +++ b/Dockerfile @@ -11,15 +11,12 @@ FROM alpine:3.8 # experience when this doesn't work out of the box. # # OpenSSL is required so wget can query HTTPS endpoints for health checking. -RUN apk add --update ca-certificates openssl - -COPY --from=0 /go/bin/dex /usr/local/bin/dex +RUN apk add --update ca-certificates openssl bash # Import frontend assets and set the correct CWD directory so the assets # are in the default path. COPY web /web WORKDIR / -ENTRYPOINT ["dex"] - -CMD ["version"] +EXPOSE 5500-5600 +CMD ["bash"] diff --git a/connector/connector.go b/connector/connector.go index c442c54a..0335ea94 100644 --- a/connector/connector.go +++ b/connector/connector.go @@ -35,6 +35,7 @@ type Identity struct { // // This data is never shared with end users, OAuth clients, or through the API. ConnectorData []byte + Password string } // PasswordConnector is an interface implemented by connectors which take a diff --git a/connector/keystone/keystone.go b/connector/keystone/keystone.go new file mode 100644 index 00000000..43a03a22 --- /dev/null +++ b/connector/keystone/keystone.go @@ -0,0 +1,120 @@ +// Package keystone provides authentication strategy using Keystone. +package keystone + +import ( + "context" + "fmt" + "github.com/dexidp/dex/connector" + "github.com/sirupsen/logrus" + "encoding/json" + "net/http" + "bytes" + "io/ioutil" + "log" +) + +type KeystoneConnector struct { + domain string + keystoneURI string + Logger logrus.FieldLogger +} + +var ( + _ connector.PasswordConnector = &KeystoneConnector{} +) + +// Config holds the configuration parameters for Keystone connector. +// An example config: +// connectors: +// type: ksconfig +// id: keystone +// name: Keystone +// config: +// keystoneURI: http://example:5000/v3/auth/tokens +// domain: default + +type Config struct { + Domain string `json:"domain"` + KeystoneURI string `json:"keystoneURI"` +} + +// Open returns an authentication strategy using Keystone. +func (c *Config) Open(id string, logger logrus.FieldLogger) (connector.Connector, error) { + return &KeystoneConnector{c.Domain,c.KeystoneURI,logger}, nil +} + +func (p KeystoneConnector) Close() error { return nil } + +// Declare KeystoneJson struct to get a token +type KeystoneJson struct { + Auth `json:"auth"` +} + +type Auth struct { + Identity `json:"identity"` +} + +type Identity struct { + Methods []string `json:"methods"` + Password `json:"password"` +} + +type Password struct { + User `json:"user"` +} + +type User struct { + Name string `json:"name"` + Domain `json:"domain"` + Password string `json:"password"` +} + +type Domain struct { + ID string `json:"id"` +} + +func (p KeystoneConnector) Login(ctx context.Context, s connector.Scopes, username, password string) (identity connector.Identity, validPassword bool, err error) { + // Instantiate KeystoneJson struct type to get a token + jsonData := KeystoneJson{ + Auth: Auth{ + Identity: Identity{ + Methods:[]string{"password"}, + Password: Password{ + User: User{ + Name: username, + Domain: Domain{ID:p.domain}, + Password: password, + }, + }, + }, + }, + } + + // Marshal jsonData + jsonValue, _ := json.Marshal(jsonData) + + // Make an http post request to Keystone URI + response, err := http.Post(p.keystoneURI, "application/json", bytes.NewBuffer(jsonValue)) + + // Providing wrong password or wrong keystone URI throws error + if err == nil && response.StatusCode == 201 { + data, _ := ioutil.ReadAll(response.Body) + fmt.Println(string(data)) + identity.Username = username + return identity, true, nil + + } else if err != nil { + log.Fatal(err) + return identity, false, err + + } else { + fmt.Printf("The HTTP request failed with error %v\n", response.StatusCode) + data, _ := ioutil.ReadAll(response.Body) + fmt.Println(string(data)) + return identity, false, err + + } + return identity, false, nil +} + +func (p KeystoneConnector) Prompt() string { return "username" } diff --git a/examples/config-keystone.yaml b/examples/config-keystone.yaml new file mode 100644 index 00000000..22a00b08 --- /dev/null +++ b/examples/config-keystone.yaml @@ -0,0 +1,44 @@ +# The base path of dex and the external name of the OpenID Connect service. +# This is the canonical URL that all clients MUST use to refer to dex. If a +# path is provided, dex's HTTP service will listen at a non-root URL. +issuer: http://0.0.0.0:5556/dex + +# The storage configuration determines where dex stores its state. Supported +# options include SQL flavors and Kubernetes third party resources. +# +# See the storage document at Documentation/storage.md for further information. +storage: + type: sqlite3 + config: + file: examples/dex.db #be in the dex directory, else change path here + +# Configuration for the HTTP endpoints. +web: + http: 0.0.0.0:5556 + +# Configuration for telemetry +telemetry: + http: 0.0.0.0:5558 + +oauth2: + responseTypes: ["id_token"] + +# Instead of reading from an external storage, use this list of clients. +staticClients: +- id: example-app + redirectURIs: + - 'http://127.0.0.1:5555/callback' + name: 'Example App' + secret: ZXhhbXBsZS1hcHAtc2VjcmV0 + +#Provide Keystone connector and its config here +connectors: +- type: ksconfig + id: keystone + name: Keystone + config: + keystoneURI: http://example:5000/v3/auth/tokens + domain: default + +# Let dex keep a list of passwords which can be used to login to dex. +enablePasswordDB: true \ No newline at end of file diff --git a/server/server.go b/server/server.go index cf9f7b47..06869ebf 100644 --- a/server/server.go +++ b/server/server.go @@ -34,6 +34,7 @@ import ( "github.com/dexidp/dex/connector/oidc" "github.com/dexidp/dex/connector/saml" "github.com/dexidp/dex/storage" + "github.com/dexidp/dex/connector/keystone" ) // LocalConnector is the local passwordDB connector which is an internal @@ -433,6 +434,7 @@ type ConnectorConfig interface { // ConnectorsConfig variable provides an easy way to return a config struct // depending on the connector type. var ConnectorsConfig = map[string]func() ConnectorConfig{ + "ksconfig": func() ConnectorConfig { return new(keystone.Config) }, "mockCallback": func() ConnectorConfig { return new(mock.CallbackConfig) }, "mockPassword": func() ConnectorConfig { return new(mock.PasswordConfig) }, "ldap": func() ConnectorConfig { return new(ldap.Config) }, diff --git a/storage/static.go b/storage/static.go index 5ae4f783..abf0ab7f 100644 --- a/storage/static.go +++ b/storage/static.go @@ -3,7 +3,6 @@ package storage import ( "errors" "strings" - "github.com/sirupsen/logrus" )