mirror of
https://github.com/openziti/zrok.git
synced 2024-12-22 06:40:50 +01:00
docs; tweaks (#404)
This commit is contained in:
parent
19d93d2825
commit
72b80bac94
@ -66,75 +66,89 @@ With this your Google OAuth client should be configured and ready.
|
||||
|
||||
## Configuring a GitHub Client ID
|
||||
|
||||
`Settings > Developer Settings > OAuth Apps > Register a new application`
|
||||
Register a new OAuth application through the GitHub settings for the account that owns the application.
|
||||
|
||||
Navigate to:`Settings > Developer Settings > OAuth Apps > Register a new application`
|
||||
|
||||
![](images/github_create_oauth_application_1.png)
|
||||
|
||||
![](images/github_create_oauth_application_2.png)
|
||||
|
||||
Authorization Callback URL: Use the address of the OAuth frontend you configured above, but add `/github/oauth` to the end of the URL.
|
||||
The "Authorized callback URL" should be configured to match the OAuth frontend address you configured at the start of this guide, with `/github/oauth` appended to the end.
|
||||
|
||||
![](images/github_create_oauth_application_3.png)
|
||||
|
||||
Create a new client secret.
|
||||
|
||||
![](images/github_create_oauth_application_4.png)
|
||||
|
||||
Save the client ID and the client secret. You'll configure these into your `frontend.yml`.
|
||||
|
||||
## Enabling Oauth on Access Point
|
||||
## Configuring your Public Frontend
|
||||
|
||||
There is a new stanza in the access point configuration.
|
||||
The public frontend configuration includes a new `oauth` section:
|
||||
|
||||
```yaml
|
||||
oauth:
|
||||
port: <host-port> #port to listen on oauth callbacks from
|
||||
redirect_url: <host-url> #redirect url to feed into oauth flow
|
||||
hash_key_raw: "<your-key>" #key we will use to sign our access token
|
||||
providers: #which providers we configure to use.
|
||||
- name: <provider-name>
|
||||
client_id: <client-id> #the client id you get from your oauth provider
|
||||
client_secret: <client-secret> #the client secret you get from your oauth provider
|
||||
```
|
||||
Currently we support the following Oauth providers:
|
||||
- google
|
||||
- github
|
||||
|
||||
In your oauth provider of choice's setup you would be prompted to create a client for accessing their services. It will ask for a redirect url. The format is: `<scheme>://<redirect_url>:<port>/<provider>/oauth` and as an example: `http://zrok.io:28080/google/oauth` This is also where you will find the client_id and client_secret.
|
||||
|
||||
The port you choose is entirely up to the deployment. Just make sure it is open to receive callbacks from your configured oauth providers.
|
||||
|
||||
redirect_url is what we will tell the oauth providers to callback with the authorization result. This will be whatever domain you've chosen to host the access server against without the scheme or port. This will get combined with the above port.
|
||||
|
||||
We then secure the response data within a zrok-access cookie. This is secured with the hash_key_raw. This can be any raw string.
|
||||
|
||||
### Required Scopes:
|
||||
- google
|
||||
- - Need access to a user's email: ./auth/userinfo.email
|
||||
|
||||
### Example
|
||||
|
||||
An example config would look something like:
|
||||
```yaml
|
||||
oauth:
|
||||
port: 28080
|
||||
redirect_url: zrok.io
|
||||
hash_key_raw: "test1234test1234"
|
||||
redirect_host: oauth.zrok.io
|
||||
redirect_port: 28080
|
||||
redirect_http_only: false
|
||||
hash_key: "<yourRandomHashKey>"
|
||||
providers:
|
||||
- name: google
|
||||
client_id: ohfwerouyr972t3riugdf89032r8y230ry.apps.googleusercontent.com
|
||||
client_secret: SDAFOHWER-qafsfgghrWERFfeqo13g
|
||||
client_id: <client-id>
|
||||
client_secret: <client-secret>
|
||||
- name: github
|
||||
client_id: <client-id>
|
||||
client_secret: <client-secret>
|
||||
|
||||
```
|
||||
|
||||
Note that the client id and secret are jumbled text and do not correlate to actual secrets.
|
||||
The `redirect_host` and `redirect_port` value should correspond with the DNS hostname and port configured as your OAuth frontend.
|
||||
|
||||
We spin up a zitadel oidc server on the specified port that handled all of the oauth handshaking. With the response we create a cookie with the name `zrok-access`.
|
||||
The `redirect_http_only` is useful in development environments where your OAuth frontend is not running behind an HTTPS reverse proxy. Should not be enabled in production environments!
|
||||
|
||||
## Enabling Oath on Share
|
||||
`hash_key` is a unique string for your installation that is used to secure the authentication payloads for your public frontend.
|
||||
|
||||
To utilize the oauth integration on the access point we need to add a few more flags to our share command. There are three new flags:
|
||||
- `provider` : This is the provider to authenticate against. Options are the same as above dependant on what the acess point is configured for
|
||||
- `oauth-domains` : A list of valid email domains that are allowed to access the service. for example `gmail.com`
|
||||
- `oauth-check-interval` : How long a `zrok-access` token is valid for before reinitializing the oauth flow. This is defaultly 3 hours.
|
||||
`providers` is a list of configured providers for this public frontend. The current implementation supports `google` and `github` as options.
|
||||
|
||||
That's all it takes!
|
||||
Both the `google` and `github` providers accept a `client_id` and `client_secret` parameter. These values are provided when you configure the OAuth clients at Google or GitHub.
|
||||
|
||||
## Enabling OAuth on a Public Share
|
||||
|
||||
With your public frontend configured to support OAuth, you can test this by creating a public share. There are new command line options to support this:
|
||||
|
||||
```
|
||||
$ zrok share public
|
||||
Error: accepts 1 arg(s), received 0
|
||||
Usage:
|
||||
zrok share public <target> [flags]
|
||||
|
||||
Flags:
|
||||
-b, --backend-mode string The backend mode {proxy, web, caddy} (default "proxy")
|
||||
--basic-auth stringArray Basic authentication users (<username:password>,...)
|
||||
--frontends stringArray Selected frontends to use for the share (default [public])
|
||||
--headless Disable TUI and run headless
|
||||
-h, --help help for public
|
||||
--insecure Enable insecure TLS certificate validation for <target>
|
||||
--oauth-check-interval duration Maximum lifetime for OAuth authentication; reauthenticate after expiry (default 3h0m0s)
|
||||
--oauth-email-domains stringArray Allow only these email domains to authenticate via OAuth
|
||||
--oauth-provider string Enable OAuth provider [google, github]
|
||||
|
||||
Global Flags:
|
||||
-p, --panic Panic instead of showing pretty errors
|
||||
-v, --verbose Enable verbose logging
|
||||
```
|
||||
|
||||
The `--oauth-provider` flag enables OAuth for the share using the specified provider.
|
||||
|
||||
The `--oauth-email-domains` flag accepts a comma-separated list of authenticated email address domains that are allowed to access the share.
|
||||
|
||||
The `--oauth-check-interval` flag specifies how frequently the authentication must be checked.
|
||||
|
||||
An example public share:
|
||||
|
||||
```
|
||||
$ zrok share public --backend-mode web --oauth-provider github --oauth-email-domains zrok.io ~/public
|
||||
```
|
||||
|
||||
Now when a user connects to your share they will be prompted with the chosen oauth provider and allowed based on your allowed domains. Simply restarting the service won't force a reauth for users either. Changing the `provider` or `oauth-check-interval` will, however.
|
@ -18,10 +18,11 @@ type Config struct {
|
||||
}
|
||||
|
||||
type OauthConfig struct {
|
||||
RedirectHost string
|
||||
RedirectPort int
|
||||
HashKeyRaw string `cf:"+secret"`
|
||||
Providers []*OauthProviderConfig
|
||||
RedirectHost string
|
||||
RedirectPort int
|
||||
RedirectHttpOnly bool
|
||||
HashKey string `cf:"+secret"`
|
||||
Providers []*OauthProviderConfig
|
||||
}
|
||||
|
||||
func (oc *OauthConfig) GetProvider(name string) *OauthProviderConfig {
|
||||
|
@ -5,12 +5,6 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/google/uuid"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -19,6 +13,11 @@ import (
|
||||
"github.com/zitadel/oidc/v2/pkg/oidc"
|
||||
"golang.org/x/oauth2"
|
||||
githubOAuth "golang.org/x/oauth2/github"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func configureGithubOauth(cfg *OauthConfig, tls bool) error {
|
||||
@ -44,11 +43,11 @@ func configureGithubOauth(cfg *OauthConfig, tls bool) error {
|
||||
}
|
||||
|
||||
hash := md5.New()
|
||||
n, err := hash.Write([]byte(cfg.HashKeyRaw))
|
||||
n, err := hash.Write([]byte(cfg.HashKey))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != len(cfg.HashKeyRaw) {
|
||||
if n != len(cfg.HashKey) {
|
||||
return errors.New("short hash")
|
||||
}
|
||||
key := hash.Sum(nil)
|
||||
@ -137,14 +136,16 @@ func configureGithubOauth(cfg *OauthConfig, tls bool) error {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
defer func() {
|
||||
_ = resp.Body.Close()
|
||||
}()
|
||||
response, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error reading response body: %v", err)
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
rDat := []githubUserResp{}
|
||||
var rDat []githubUserResp
|
||||
err = json.Unmarshal(response, &rDat)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error unmarshalling google oauth response: %v", err)
|
||||
|
@ -5,12 +5,6 @@ import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/golang-jwt/jwt/v5"
|
||||
"github.com/google/uuid"
|
||||
"github.com/sirupsen/logrus"
|
||||
@ -19,6 +13,11 @@ import (
|
||||
"github.com/zitadel/oidc/v2/pkg/oidc"
|
||||
"golang.org/x/oauth2"
|
||||
googleOauth "golang.org/x/oauth2/google"
|
||||
"io"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func configureGoogleOauth(cfg *OauthConfig, tls bool) error {
|
||||
@ -45,11 +44,11 @@ func configureGoogleOauth(cfg *OauthConfig, tls bool) error {
|
||||
}
|
||||
|
||||
hash := md5.New()
|
||||
n, err := hash.Write([]byte(cfg.HashKeyRaw))
|
||||
n, err := hash.Write([]byte(cfg.HashKey))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if n != len(cfg.HashKeyRaw) {
|
||||
if n != len(cfg.HashKey) {
|
||||
return errors.New("short hash")
|
||||
}
|
||||
key := hash.Sum(nil)
|
||||
@ -124,7 +123,9 @@ func configureGoogleOauth(cfg *OauthConfig, tls bool) error {
|
||||
http.Error(w, err.Error(), http.StatusInternalServerError)
|
||||
return
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
defer func() {
|
||||
_ = resp.Body.Close()
|
||||
}()
|
||||
response, err := io.ReadAll(resp.Body)
|
||||
if err != nil {
|
||||
logrus.Errorf("Error reading response body: %v", err)
|
||||
|
@ -33,11 +33,11 @@ func NewHTTP(cfg *Config) (*HttpFrontend, error) {
|
||||
var key []byte
|
||||
if cfg.Oauth != nil {
|
||||
hash := md5.New()
|
||||
n, err := hash.Write([]byte(cfg.Oauth.HashKeyRaw))
|
||||
n, err := hash.Write([]byte(cfg.Oauth.HashKey))
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if n != len(cfg.Oauth.HashKeyRaw) {
|
||||
if n != len(cfg.Oauth.HashKey) {
|
||||
return nil, errors.New("short hash")
|
||||
}
|
||||
key = hash.Sum(nil)
|
||||
@ -80,17 +80,17 @@ func NewHTTP(cfg *Config) (*HttpFrontend, error) {
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (self *HttpFrontend) Run() error {
|
||||
return http.ListenAndServe(self.cfg.Address, self.handler)
|
||||
func (f *HttpFrontend) Run() error {
|
||||
return http.ListenAndServe(f.cfg.Address, f.handler)
|
||||
}
|
||||
|
||||
type zitiDialContext struct {
|
||||
ctx ziti.Context
|
||||
}
|
||||
|
||||
func (self *zitiDialContext) Dial(_ context.Context, _ string, addr string) (net.Conn, error) {
|
||||
func (c *zitiDialContext) Dial(_ context.Context, _ string, addr string) (net.Conn, error) {
|
||||
shrToken := strings.Split(addr, ":")[0] // ignore :port (we get passed 'host:port')
|
||||
conn, err := self.ctx.Dial(shrToken)
|
||||
conn, err := c.ctx.Dial(shrToken)
|
||||
if err != nil {
|
||||
return conn, err
|
||||
}
|
||||
@ -344,11 +344,15 @@ func SetZrokCookie(w http.ResponseWriter, domain, email, accessToken, provider s
|
||||
func basicAuthRequired(w http.ResponseWriter, realm string) {
|
||||
w.Header().Set("WWW-Authenticate", `Basic realm="`+realm+`"`)
|
||||
w.WriteHeader(401)
|
||||
w.Write([]byte("No Authorization\n"))
|
||||
_, _ = w.Write([]byte("No Authorization\n"))
|
||||
}
|
||||
|
||||
func oauthLoginRequired(w http.ResponseWriter, r *http.Request, shrToken string, pcfg *Config, provider, target string, authCheckInterval time.Duration) {
|
||||
http.Redirect(w, r, fmt.Sprintf("http://%s.%s:%d/%s/login?targethost=%s&checkInterval=%s", shrToken, pcfg.Oauth.RedirectHost, pcfg.Oauth.RedirectPort, provider, url.QueryEscape(target), authCheckInterval.String()), http.StatusFound)
|
||||
scheme := "https"
|
||||
if pcfg.Oauth != nil && pcfg.Oauth.RedirectHttpOnly {
|
||||
scheme = "http"
|
||||
}
|
||||
http.Redirect(w, r, fmt.Sprintf("%s://%s.%s:%d/%s/login?targethost=%s&checkInterval=%s", scheme, shrToken, pcfg.Oauth.RedirectHost, pcfg.Oauth.RedirectPort, provider, url.QueryEscape(target), authCheckInterval.String()), http.StatusFound)
|
||||
}
|
||||
|
||||
func resolveService(hostMatch string, host string) string {
|
||||
|
@ -4,10 +4,13 @@
|
||||
#
|
||||
#host_match: zrok.io
|
||||
|
||||
# The OAuth configuration is used when enabling OAuth authentication with your public frontend.
|
||||
#
|
||||
#oauth:
|
||||
# redirect_host: zrok.io
|
||||
# redirect_host: oauth.zrok.io
|
||||
# redirect_port: 28080
|
||||
# hash_key_raw: "test1234test1234"
|
||||
# redirect_http_only: false
|
||||
# hash_key: "<yourRandomHashKey>"
|
||||
# providers:
|
||||
# - name: google
|
||||
# client_id: <client-id>
|
||||
|
Loading…
Reference in New Issue
Block a user