new custom oAuth authentication method, added "local" auth method as default

pull/702/head
hunterlong 2020-06-25 21:46:09 -07:00
parent 202695ba20
commit 08e5d81c3c
9 changed files with 149 additions and 14 deletions

View File

@ -11,6 +11,7 @@
- Added Google oAuth email/domain user restrictions - Added Google oAuth email/domain user restrictions
- Modified notifiers to use dereferenced services and failures - Modified notifiers to use dereferenced services and failures
- Added core.Example() function for testing - Added core.Example() function for testing
- Added Custom oAuth Authentication method
# 0.90.55 (06-18-2020) # 0.90.55 (06-18-2020)
- Added 404 page - Added 404 page

View File

@ -37,6 +37,10 @@
<font-awesome-icon :icon="['fab', 'google']" /> Login with Google <font-awesome-icon :icon="['fab', 'google']" /> Login with Google
</a> </a>
<a v-if="oauth && oauth.custom_client_id" @click.prevent="Customlogin" href="#" class="btn btn-block btn-outline-dark">
<font-awesome-icon :icon="['fas', 'address-card']" /> Login with {{oauth.custom_name}}
</a>
</div> </div>
</template> </template>
@ -95,6 +99,9 @@
}, },
Googlelogin() { Googlelogin() {
window.location = `https://accounts.google.com/signin/oauth?client_id=${this.oauth.google_client_id}&redirect_uri=${this.core.domain}/oauth/google&response_type=code&scope=https://www.googleapis.com/auth/userinfo.profile+https://www.googleapis.com/auth/userinfo.email` window.location = `https://accounts.google.com/signin/oauth?client_id=${this.oauth.google_client_id}&redirect_uri=${this.core.domain}/oauth/google&response_type=code&scope=https://www.googleapis.com/auth/userinfo.profile+https://www.googleapis.com/auth/userinfo.email`
},
Customlogin() {
window.location = `${this.oauth.custom_endpoint_auth}?client_id=${this.oauth.custom_client_id}&redirect_uri=${this.core.domain}/oauth/custom${this.oauth.custom_scopes !== "" ? "&scope="+this.oauth.custom_scopes : "" }`
} }
} }
} }

View File

@ -168,6 +168,70 @@
</div> </div>
</div> </div>
<div class="card text-black-50 bg-white mb-3">
<div class="card-header">Custom oAuth Settings</div>
<div class="card-body">
<div class="form-group row mt-3">
<label for="custom_name" class="col-sm-4 col-form-label">Custom Name</label>
<div class="col-sm-8">
<input v-model="oauth.custom_name" type="text" class="form-control" id="custom_name" required>
</div>
</div>
<div class="form-group row mt-3">
<label for="custom_client" class="col-sm-4 col-form-label">Client ID</label>
<div class="col-sm-8">
<input v-model="oauth.custom_client_id" type="text" class="form-control" id="custom_client" required>
</div>
</div>
<div class="form-group row">
<label for="custom_secret" class="col-sm-4 col-form-label">Client Secret</label>
<div class="col-sm-8">
<input v-model="oauth.custom_client_secret" type="text" class="form-control" id="custom_secret" required>
</div>
</div>
<div class="form-group row">
<label for="custom_endpoint" class="col-sm-4 col-form-label">Auth Endpoint</label>
<div class="col-sm-8">
<input v-model="oauth.custom_endpoint_auth" type="text" class="form-control" id="custom_endpoint" required>
</div>
</div>
<div class="form-group row">
<label for="custom_endpoint_token" class="col-sm-4 col-form-label">Token Endpoint</label>
<div class="col-sm-8">
<input v-model="oauth.custom_endpoint_token" type="text" class="form-control" id="custom_endpoint_token" required>
</div>
</div>
<div class="form-group row">
<label for="custom_scopes" class="col-sm-4 col-form-label">Scopes</label>
<div class="col-sm-8">
<input v-model="oauth.custom_scopes" type="text" class="form-control" id="custom_scopes">
<small>Optional comma delimited list of oauth scopes</small>
</div>
</div>
<div class="form-group row">
<label for="switch-custom-oauth" class="col-sm-4 col-form-label">Enable Custom Login</label>
<div class="col-md-8 col-xs-12 mt-1">
<span @click="custom_enabled = !!custom_enabled" class="switch float-left">
<input v-model="custom_enabled" type="checkbox" class="switch" id="switch-custom-oauth" :checked="custom_enabled">
<label for="switch-custom-oauth"> </label>
</span>
</div>
</div>
<div class="form-group row">
<label for="slack_callback" class="col-sm-4 col-form-label">Callback URL</label>
<div class="col-sm-8">
<div class="input-group">
<input v-bind:value="`${core.domain}/oauth/custom`" type="text" class="form-control" id="custom_callback" readonly>
<div class="input-group-append copy-btn">
<button @click.prevent="copy(`${core.domain}/oauth/custom`)" class="btn btn-outline-secondary" type="button">Copy</button>
</div>
</div>
</div>
</div>
</div>
</div>
<button class="btn btn-primary btn-block" @click.prevent="saveOAuth" type="submit" :disabled="loading"> <button class="btn btn-primary btn-block" @click.prevent="saveOAuth" type="submit" :disabled="loading">
<font-awesome-icon v-if="loading" icon="circle-notch" class="mr-2" spin/> Save OAuth Settings <font-awesome-icon v-if="loading" icon="circle-notch" class="mr-2" spin/> Save OAuth Settings
</button> </button>
@ -191,6 +255,7 @@
slack_enabled: false, slack_enabled: false,
github_enabled: false, github_enabled: false,
local_enabled: false, local_enabled: false,
custom_enabled: false,
loading: false, loading: false,
oauth: { oauth: {
gh_client_id: "", gh_client_id: "",
@ -204,7 +269,13 @@
slack_client_id: "", slack_client_id: "",
slack_client_secret: "", slack_client_secret: "",
slack_team: "", slack_team: "",
slack_users: "" slack_users: "",
custom_name: "",
custom_client_id: "",
custom_client_secret: "",
custom_endpoint_auth: "",
custom_endpoint_token: "",
custom_scopes: "",
} }
} }
}, },
@ -214,6 +285,7 @@
this.github_enabled = this.has('github') this.github_enabled = this.has('github')
this.google_enabled = this.has('google') this.google_enabled = this.has('google')
this.slack_enabled = this.has('slack') this.slack_enabled = this.has('slack')
this.custom_enabled = this.has('custom')
}, },
methods: { methods: {
providers() { providers() {
@ -230,6 +302,9 @@
if (this.slack_enabled) { if (this.slack_enabled) {
providers.push("slack") providers.push("slack")
} }
if (this.custom_enabled) {
providers.push("custom")
}
return providers.join(",") return providers.join(",")
}, },
has(val) { has(val) {

View File

@ -29,6 +29,8 @@ func oauthHandler(w http.ResponseWriter, r *http.Request) {
oauth, err = githubOAuth(r) oauth, err = githubOAuth(r)
case "slack": case "slack":
oauth, err = slackOAuth(r) oauth, err = slackOAuth(r)
case "custom":
oauth, err = customOAuth(r)
} }
if err != nil { if err != nil {

40
handlers/oauth_custom.go Normal file
View File

@ -0,0 +1,40 @@
package handlers
import (
"github.com/statping/statping/types/core"
"github.com/statping/statping/types/errors"
"golang.org/x/oauth2"
"net/http"
"strings"
)
func customOAuth(r *http.Request) (*oAuth, error) {
auth := core.App.OAuth
code := r.URL.Query().Get("code")
scopes := strings.Split(auth.CustomScopes, ",")
config := &oauth2.Config{
ClientID: auth.CustomClientID,
ClientSecret: auth.CustomClientSecret,
Endpoint: oauth2.Endpoint{
AuthURL: auth.CustomEndpointAuth,
TokenURL: auth.CustomEndpointToken,
},
RedirectURL: core.App.Domain + basePath + "oauth/custom",
Scopes: scopes,
}
gg, err := config.Exchange(r.Context(), code)
if err != nil {
return nil, err
}
if !gg.Valid() {
return nil, errors.New("oauth token is not valid")
}
return &oAuth{
Token: gg,
}, nil
}

View File

@ -20,6 +20,7 @@ func githubOAuth(r *http.Request) (*oAuth, error) {
ClientID: auth.GithubClientID, ClientID: auth.GithubClientID,
ClientSecret: auth.GithubClientSecret, ClientSecret: auth.GithubClientSecret,
Endpoint: github.Endpoint, Endpoint: github.Endpoint,
RedirectURL: core.App.Domain + basePath + "oauth/github",
} }
gg, err := config.Exchange(r.Context(), code) gg, err := config.Exchange(r.Context(), code)

View File

@ -20,7 +20,7 @@ func googleOAuth(r *http.Request) (*oAuth, error) {
ClientID: auth.GoogleClientID, ClientID: auth.GoogleClientID,
ClientSecret: auth.GoogleClientSecret, ClientSecret: auth.GoogleClientSecret,
Endpoint: google.Endpoint, Endpoint: google.Endpoint,
RedirectURL: core.App.Domain + "/oauth/google", RedirectURL: core.App.Domain + basePath + "oauth/google",
} }
gg, err := config.Exchange(r.Context(), code) gg, err := config.Exchange(r.Context(), code)

View File

@ -28,6 +28,8 @@ func Samples() error {
apiSecret = utils.RandomString(32) apiSecret = utils.RandomString(32)
} }
oauth := OAuth{Providers: "local"}
core := &Core{ core := &Core{
Name: utils.Params.GetString("NAME"), Name: utils.Params.GetString("NAME"),
Description: utils.Params.GetString("DESCRIPTION"), Description: utils.Params.GetString("DESCRIPTION"),
@ -38,6 +40,7 @@ func Samples() error {
Footer: null.NewNullString(""), Footer: null.NewNullString(""),
MigrationId: utils.Now().Unix(), MigrationId: utils.Now().Unix(),
Language: utils.Params.GetString("LANGUAGE"), Language: utils.Params.GetString("LANGUAGE"),
OAuth: oauth,
} }
return core.Create() return core.Create()

View File

@ -43,18 +43,24 @@ type Core struct {
} }
type OAuth struct { type OAuth struct {
Providers string `gorm:"column:oauth_providers;" json:"oauth_providers"` Providers string `gorm:"column:oauth_providers;" json:"oauth_providers"`
GithubClientID string `gorm:"column:gh_client_id" json:"gh_client_id"` GithubClientID string `gorm:"column:gh_client_id" json:"gh_client_id"`
GithubClientSecret string `gorm:"column:gh_client_secret" json:"gh_client_secret" scope:"admin"` GithubClientSecret string `gorm:"column:gh_client_secret" json:"gh_client_secret" scope:"admin"`
GithubUsers string `gorm:"column:gh_users" json:"gh_users" scope:"admin"` GithubUsers string `gorm:"column:gh_users" json:"gh_users" scope:"admin"`
GithubOrgs string `gorm:"column:gh_orgs" json:"gh_orgs" scope:"admin"` GithubOrgs string `gorm:"column:gh_orgs" json:"gh_orgs" scope:"admin"`
GoogleClientID string `gorm:"column:google_client_id" json:"google_client_id"` GoogleClientID string `gorm:"column:google_client_id" json:"google_client_id"`
GoogleClientSecret string `gorm:"column:google_client_secret" json:"google_client_secret" scope:"admin"` GoogleClientSecret string `gorm:"column:google_client_secret" json:"google_client_secret" scope:"admin"`
GoogleUsers string `gorm:"column:google_users" json:"google_users" scope:"admin"` GoogleUsers string `gorm:"column:google_users" json:"google_users" scope:"admin"`
SlackClientID string `gorm:"column:slack_client_id" json:"slack_client_id"` SlackClientID string `gorm:"column:slack_client_id" json:"slack_client_id"`
SlackClientSecret string `gorm:"column:slack_client_secret" json:"slack_client_secret" scope:"admin"` SlackClientSecret string `gorm:"column:slack_client_secret" json:"slack_client_secret" scope:"admin"`
SlackTeam string `gorm:"column:slack_team" json:"slack_team" scope:"admin"` SlackTeam string `gorm:"column:slack_team" json:"slack_team" scope:"admin"`
SlackUsers string `gorm:"column:slack_users" json:"slack_users" scope:"admin"` SlackUsers string `gorm:"column:slack_users" json:"slack_users" scope:"admin"`
CustomName string `gorm:"column:custom_name" json:"custom_name"`
CustomClientID string `gorm:"column:custom_client_id" json:"custom_client_id"`
CustomClientSecret string `gorm:"column:custom_client_secret" json:"custom_client_secret" scope:"admin"`
CustomEndpointAuth string `gorm:"column:custom_endpoint_auth" json:"custom_endpoint_auth"`
CustomEndpointToken string `gorm:"column:custom_endpoint_token" json:"custom_endpoint_token" scope:"admin"`
CustomScopes string `gorm:"column:custom_scopes" json:"custom_scopes"`
} }
// AllNotifiers contains all the Notifiers loaded // AllNotifiers contains all the Notifiers loaded