mirror of https://github.com/statping/statping
oauth fixes, login cookies fixes
parent
7be131d0cf
commit
6f0f712bad
|
@ -9,7 +9,7 @@ const errorReporter = "https://bed4d75404924cb3a799e370733a1b64@sentry.statping.
|
|||
|
||||
class Api {
|
||||
constructor() {
|
||||
|
||||
axios.defaults.withCredentials = true
|
||||
}
|
||||
|
||||
async oauth() {
|
||||
|
@ -251,17 +251,13 @@ class Api {
|
|||
}
|
||||
|
||||
token() {
|
||||
const tk = $cookies.get(tokenKey)
|
||||
if (!tk) {
|
||||
return {admin: false};
|
||||
}
|
||||
return tk;
|
||||
return $cookies.get(tokenKey);
|
||||
}
|
||||
|
||||
authToken() {
|
||||
const tk = $cookies.get(tokenKey)
|
||||
if (tk.token) {
|
||||
return {'Authorization': 'Bearer ' + tk.token};
|
||||
if (tk) {
|
||||
return {'Authorization': 'Bearer ' + tk};
|
||||
} else {
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -52,7 +52,7 @@
|
|||
this.$store.commit('setHasAllData', false)
|
||||
this.$store.commit('setToken', null)
|
||||
this.$store.commit('setAdmin', false)
|
||||
this.$cookies.remove("statping_auth")
|
||||
// this.$cookies.remove("statping_auth")
|
||||
await this.$router.push('/logout')
|
||||
}
|
||||
}
|
||||
|
|
|
@ -80,9 +80,8 @@
|
|||
if (auth.error) {
|
||||
this.error = true
|
||||
} else if (auth.token) {
|
||||
const u = {username: this.username, admin: auth.admin, token: auth.token}
|
||||
this.$cookies.set("statping_auth", JSON.stringify(u))
|
||||
this.$store.dispatch('loadAdmin')
|
||||
// this.$cookies.set("statping_auth", auth.token)
|
||||
await this.$store.dispatch('loadAdmin')
|
||||
this.$store.commit('setAdmin', auth.admin)
|
||||
this.$router.push('/dashboard')
|
||||
}
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
<template>
|
||||
<form @submit.prevent="saveOAuth">
|
||||
{{core.oauth}}
|
||||
<div class="card text-black-50 bg-white mb-3">
|
||||
<div class="card-header">Internal Login</div>
|
||||
<div class="card-body">
|
||||
|
@ -146,8 +145,8 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<button class="btn btn-primary btn-block" @click.prevent="saveOAuth" type="submit">
|
||||
Save OAuth Settings
|
||||
<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
|
||||
</button>
|
||||
|
||||
</form>
|
||||
|
@ -162,9 +161,6 @@
|
|||
core() {
|
||||
return this.$store.getters.core
|
||||
},
|
||||
auth() {
|
||||
return this.$store.getters.oauth
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
|
@ -172,6 +168,7 @@
|
|||
slack_enabled: false,
|
||||
github_enabled: false,
|
||||
local_enabled: false,
|
||||
loading: false,
|
||||
oauth: {
|
||||
gh_client_id: "",
|
||||
gh_client_secret: "",
|
||||
|
@ -185,8 +182,8 @@
|
|||
}
|
||||
}
|
||||
},
|
||||
mounted() {
|
||||
this.oauth = this.auth
|
||||
async mounted() {
|
||||
this.oauth = await Api.oauth()
|
||||
this.local_enabled = this.has('local')
|
||||
this.github_enabled = this.has('github')
|
||||
this.google_enabled = this.has('google')
|
||||
|
@ -216,12 +213,12 @@
|
|||
return this.oauth.oauth_providers.split(",").includes(val)
|
||||
},
|
||||
async saveOAuth() {
|
||||
let c = this.core
|
||||
c.oauth = this.oauth
|
||||
c.oauth.oauth_providers = this.providers()
|
||||
await Api.oauth_save(c)
|
||||
this.loading = true
|
||||
this.oauth.oauth_providers = this.providers()
|
||||
await Api.oauth_save(this.oauth)
|
||||
const oauth = await Api.oauth()
|
||||
this.$store.commit('setOAuth', oauth)
|
||||
this.loading = false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -38,7 +38,7 @@ const routes = [
|
|||
beforeEnter: async (to, from, next) => {
|
||||
if (to.matched.some(record => record.meta.requiresAuth)) {
|
||||
let tk = await Api.token()
|
||||
if (to.path !== '/login' && !tk.admin) {
|
||||
if (to.path !== '/login' && !tk) {
|
||||
next('/login')
|
||||
return
|
||||
}
|
||||
|
|
|
@ -147,9 +147,9 @@ export default new Vuex.Store({
|
|||
const core = await Api.core()
|
||||
const token = await Api.token()
|
||||
context.commit("setCore", core);
|
||||
context.commit('setAdmin', token.admin)
|
||||
context.commit('setAdmin', token)
|
||||
context.commit('setCore', core)
|
||||
context.commit('setUser', token.token!==undefined)
|
||||
context.commit('setUser', token!==undefined)
|
||||
},
|
||||
async loadRequired(context) {
|
||||
const groups = await Api.groups()
|
||||
|
@ -170,14 +170,8 @@ export default new Vuex.Store({
|
|||
const messages = await Api.messages()
|
||||
context.commit("setMessages", messages)
|
||||
context.commit("setHasPublicData", true)
|
||||
try {
|
||||
const checkins = await Api.checkins()
|
||||
context.commit("setCheckins", checkins);
|
||||
} catch(e) {
|
||||
window.console.error(e)
|
||||
await Api.logout()
|
||||
return
|
||||
}
|
||||
const checkins = await Api.checkins()
|
||||
context.commit("setCheckins", checkins);
|
||||
const notifiers = await Api.notifiers()
|
||||
context.commit("setNotifiers", notifiers);
|
||||
const users = await Api.users()
|
||||
|
|
|
@ -3,14 +3,23 @@ module.exports = {
|
|||
assetsDir: 'assets',
|
||||
filenameHashing: false,
|
||||
devServer: {
|
||||
proxy: {
|
||||
disableHostCheck: true,
|
||||
proxyTable: {
|
||||
'/api': {
|
||||
logLevel: 'debug',
|
||||
target: 'http://0.0.0.0:8585'
|
||||
target: 'http://0.0.0.0:8585',
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
'^/api': ''
|
||||
}
|
||||
},
|
||||
'/oauth': {
|
||||
logLevel: 'debug',
|
||||
target: 'http://0.0.0.0:8585/oauth/'
|
||||
target: 'http://0.0.0.0:8585',
|
||||
changeOrigin: true,
|
||||
pathRewrite: {
|
||||
'^/oauth': ''
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -46,13 +46,20 @@ func apiRenewHandler(w http.ResponseWriter, r *http.Request) {
|
|||
|
||||
func apiUpdateOAuthHandler(w http.ResponseWriter, r *http.Request) {
|
||||
var c core.OAuth
|
||||
err := DecodeJSON(r, &c)
|
||||
if err != nil {
|
||||
if err := DecodeJSON(r, &c); err != nil {
|
||||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
|
||||
app := core.App
|
||||
app.OAuth = c
|
||||
if err := app.Update(); err != nil {
|
||||
sendErrorJson(err, w, r)
|
||||
return
|
||||
}
|
||||
|
||||
fmt.Println(app)
|
||||
|
||||
sendJsonAction(app.OAuth, "update", w, r)
|
||||
}
|
||||
|
||||
|
|
|
@ -19,7 +19,7 @@ const (
|
|||
)
|
||||
|
||||
var (
|
||||
jwtKey string
|
||||
jwtKey []byte
|
||||
httpServer *http.Server
|
||||
usingSSL bool
|
||||
mainTmpl = `{{define "main" }} {{ template "base" . }} {{ end }}`
|
||||
|
@ -96,7 +96,11 @@ func IsFullAuthenticated(r *http.Request) bool {
|
|||
if ok := hasAuthorizationHeader(r); ok {
|
||||
return true
|
||||
}
|
||||
return IsAdmin(r)
|
||||
claim, err := getJwtToken(r)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return claim.Admin
|
||||
}
|
||||
|
||||
// ScopeName will show private JSON fields in the API.
|
||||
|
|
|
@ -33,7 +33,7 @@ func setJwtToken(user *users.User, w http.ResponseWriter) (JwtClaim, string) {
|
|||
ExpiresAt: expirationTime.Unix(),
|
||||
}}
|
||||
token := jwt.NewWithClaims(jwt.SigningMethodHS256, jwtClaim)
|
||||
tokenString, err := token.SignedString([]byte(jwtKey))
|
||||
tokenString, err := token.SignedString(jwtKey)
|
||||
if err != nil {
|
||||
log.Errorln("error setting token: ", err)
|
||||
}
|
||||
|
@ -44,6 +44,7 @@ func setJwtToken(user *users.User, w http.ResponseWriter) (JwtClaim, string) {
|
|||
Value: tokenString,
|
||||
Expires: expirationTime,
|
||||
MaxAge: int(time.Duration(72 * time.Hour).Seconds()),
|
||||
Path: "/",
|
||||
})
|
||||
return jwtClaim, tokenString
|
||||
}
|
||||
|
@ -56,11 +57,12 @@ func getJwtToken(r *http.Request) (JwtClaim, error) {
|
|||
}
|
||||
return JwtClaim{}, err
|
||||
}
|
||||
tknStr := c.Value
|
||||
|
||||
var claims JwtClaim
|
||||
tkn, err := jwt.ParseWithClaims(tknStr, &claims, func(token *jwt.Token) (interface{}, error) {
|
||||
return []byte(jwtKey), nil
|
||||
tkn, err := jwt.ParseWithClaims(c.Value, &claims, func(token *jwt.Token) (interface{}, error) {
|
||||
return jwtKey, nil
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
if err == jwt.ErrSignatureInvalid {
|
||||
return JwtClaim{}, err
|
||||
|
|
|
@ -9,7 +9,6 @@ import (
|
|||
"github.com/statping/statping/types/users"
|
||||
"github.com/statping/statping/utils"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/github"
|
||||
"golang.org/x/oauth2/google"
|
||||
"golang.org/x/oauth2/slack"
|
||||
"net/http"
|
||||
|
@ -51,40 +50,18 @@ func oauthHandler(w http.ResponseWriter, r *http.Request) {
|
|||
}
|
||||
|
||||
func oauthLogin(oauth *oAuth, w http.ResponseWriter, r *http.Request) {
|
||||
log.Infoln(oauth)
|
||||
user := &users.User{
|
||||
Id: 0,
|
||||
Username: oauth.Username,
|
||||
Email: oauth.Email,
|
||||
Admin: null.NewNullBool(true),
|
||||
}
|
||||
log.Infoln(fmt.Sprintf("OAuth User %s logged in from IP %s", oauth.Email, r.RemoteAddr))
|
||||
log.Infoln(fmt.Sprintf("OAuth %s User %s logged in from IP %s", oauth.Type, oauth.Email, r.RemoteAddr))
|
||||
|
||||
setJwtToken(user, w)
|
||||
|
||||
//returnJson(user, w, r)
|
||||
http.Redirect(w, r, core.App.Domain, http.StatusPermanentRedirect)
|
||||
}
|
||||
|
||||
func githubOAuth(r *http.Request) (*oAuth, error) {
|
||||
c := *core.App
|
||||
code := r.URL.Query().Get("code")
|
||||
|
||||
config := &oauth2.Config{
|
||||
ClientID: c.OAuth.GithubClientID,
|
||||
ClientSecret: c.OAuth.GithubClientSecret,
|
||||
Endpoint: github.Endpoint,
|
||||
}
|
||||
|
||||
gg, err := config.Exchange(r.Context(), code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &oAuth{
|
||||
Token: gg.AccessToken,
|
||||
RefreshToken: gg.RefreshToken,
|
||||
Valid: gg.Valid(),
|
||||
}, nil
|
||||
http.Redirect(w, r, core.App.Domain+"/dashboard", http.StatusPermanentRedirect)
|
||||
}
|
||||
|
||||
func googleOAuth(r *http.Request) (*oAuth, error) {
|
||||
|
|
|
@ -0,0 +1,99 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"github.com/statping/statping/types/core"
|
||||
"github.com/statping/statping/utils"
|
||||
"golang.org/x/oauth2"
|
||||
"golang.org/x/oauth2/github"
|
||||
"net/http"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
func githubOAuth(r *http.Request) (*oAuth, error) {
|
||||
c := *core.App
|
||||
code := r.URL.Query().Get("code")
|
||||
|
||||
config := &oauth2.Config{
|
||||
ClientID: c.OAuth.GithubClientID,
|
||||
ClientSecret: c.OAuth.GithubClientSecret,
|
||||
Endpoint: github.Endpoint,
|
||||
}
|
||||
|
||||
gg, err := config.Exchange(r.Context(), code)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
headers := []string{
|
||||
"Accept=application/vnd.github.machine-man-preview+json",
|
||||
"Authorization=token " + gg.AccessToken,
|
||||
}
|
||||
|
||||
resp, _, err := utils.HttpRequest("https://api.github.com/user", "GET", nil, headers, nil, 10*time.Second, true, nil)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var user githubUser
|
||||
if err := json.Unmarshal(resp, &user); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &oAuth{
|
||||
Token: gg.AccessToken,
|
||||
RefreshToken: gg.RefreshToken,
|
||||
Valid: gg.Valid(),
|
||||
Username: strings.ToLower(user.Name),
|
||||
Email: strings.ToLower(user.Email),
|
||||
Type: "github",
|
||||
}, nil
|
||||
}
|
||||
|
||||
type githubUser struct {
|
||||
Login string `json:"login"`
|
||||
ID int `json:"id"`
|
||||
NodeID string `json:"node_id"`
|
||||
AvatarURL string `json:"avatar_url"`
|
||||
GravatarID string `json:"gravatar_id"`
|
||||
URL string `json:"url"`
|
||||
HTMLURL string `json:"html_url"`
|
||||
FollowersURL string `json:"followers_url"`
|
||||
FollowingURL string `json:"following_url"`
|
||||
GistsURL string `json:"gists_url"`
|
||||
StarredURL string `json:"starred_url"`
|
||||
SubscriptionsURL string `json:"subscriptions_url"`
|
||||
OrganizationsURL string `json:"organizations_url"`
|
||||
ReposURL string `json:"repos_url"`
|
||||
EventsURL string `json:"events_url"`
|
||||
ReceivedEventsURL string `json:"received_events_url"`
|
||||
Type string `json:"type"`
|
||||
SiteAdmin bool `json:"site_admin"`
|
||||
Name string `json:"name"`
|
||||
Company string `json:"company"`
|
||||
Blog string `json:"blog"`
|
||||
Location string `json:"location"`
|
||||
Email string `json:"email"`
|
||||
Hireable bool `json:"hireable"`
|
||||
Bio string `json:"bio"`
|
||||
TwitterUsername string `json:"twitter_username"`
|
||||
PublicRepos int `json:"public_repos"`
|
||||
PublicGists int `json:"public_gists"`
|
||||
Followers int `json:"followers"`
|
||||
Following int `json:"following"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
UpdatedAt time.Time `json:"updated_at"`
|
||||
PrivateGists int `json:"private_gists"`
|
||||
TotalPrivateRepos int `json:"total_private_repos"`
|
||||
OwnedPrivateRepos int `json:"owned_private_repos"`
|
||||
DiskUsage int `json:"disk_usage"`
|
||||
Collaborators int `json:"collaborators"`
|
||||
TwoFactorAuthentication bool `json:"two_factor_authentication"`
|
||||
Plan struct {
|
||||
Name string `json:"name"`
|
||||
Space int `json:"space"`
|
||||
PrivateRepos int `json:"private_repos"`
|
||||
Collaborators int `json:"collaborators"`
|
||||
} `json:"plan"`
|
||||
}
|
|
@ -1,12 +1,10 @@
|
|||
package handlers
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
sentryhttp "github.com/getsentry/sentry-go/http"
|
||||
"github.com/gorilla/mux"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
"github.com/statping/statping/source"
|
||||
"github.com/statping/statping/types/core"
|
||||
"github.com/statping/statping/utils"
|
||||
"net/http"
|
||||
"net/http/pprof"
|
||||
|
@ -192,5 +190,5 @@ func resetRouter() {
|
|||
}
|
||||
|
||||
func resetCookies() {
|
||||
jwtKey = fmt.Sprintf("%s_%d", core.App.ApiSecret, utils.Now().Nanosecond())
|
||||
jwtKey = []byte(utils.NewSHA256Hash())
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue