replace zxq.co/ripple/hanayo
This commit is contained in:
74
vendor/github.com/felipeweb/osin-mysql/.gitignore
generated
vendored
Normal file
74
vendor/github.com/felipeweb/osin-mysql/.gitignore
generated
vendored
Normal file
@@ -0,0 +1,74 @@
|
||||
### JetBrains template
|
||||
# Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio
|
||||
|
||||
*.iml
|
||||
|
||||
## Directory-based project format:
|
||||
.idea/
|
||||
# if you remove the above rule, at least ignore the following:
|
||||
|
||||
# User-specific stuff:
|
||||
# .idea/workspace.xml
|
||||
# .idea/tasks.xml
|
||||
# .idea/dictionaries
|
||||
|
||||
# Sensitive or high-churn files:
|
||||
# .idea/dataSources.ids
|
||||
# .idea/dataSources.xml
|
||||
# .idea/sqlDataSources.xml
|
||||
# .idea/dynamic.xml
|
||||
# .idea/uiDesigner.xml
|
||||
|
||||
# Gradle:
|
||||
# .idea/gradle.xml
|
||||
# .idea/libraries
|
||||
|
||||
# Mongo Explorer plugin:
|
||||
# .idea/mongoSettings.xml
|
||||
|
||||
## File-based project format:
|
||||
*.ipr
|
||||
*.iws
|
||||
|
||||
## Plugin-specific files:
|
||||
|
||||
# IntelliJ
|
||||
/out/
|
||||
|
||||
# mpeltonen/sbt-idea plugin
|
||||
.idea_modules/
|
||||
|
||||
# JIRA plugin
|
||||
atlassian-ide-plugin.xml
|
||||
|
||||
# Crashlytics plugin (for Android Studio and IntelliJ)
|
||||
com_crashlytics_export_strings.xml
|
||||
crashlytics.properties
|
||||
crashlytics-build.properties
|
||||
### Go template
|
||||
# Compiled Object files, Static and Dynamic libs (Shared Objects)
|
||||
*.o
|
||||
*.a
|
||||
*.so
|
||||
|
||||
# Folders
|
||||
_obj
|
||||
_test
|
||||
|
||||
# Architecture specific extensions/prefixes
|
||||
*.[568vq]
|
||||
[568vq].out
|
||||
|
||||
*.cgo1.go
|
||||
*.cgo2.c
|
||||
_cgo_defun.c
|
||||
_cgo_gotypes.go
|
||||
_cgo_export.*
|
||||
|
||||
_testmain.go
|
||||
|
||||
*.exe
|
||||
*.test
|
||||
*.prof
|
||||
|
||||
# Created by .ignore support plugin (hsz.mobi)
|
20
vendor/github.com/felipeweb/osin-mysql/.travis.yml
generated
vendored
Normal file
20
vendor/github.com/felipeweb/osin-mysql/.travis.yml
generated
vendored
Normal file
@@ -0,0 +1,20 @@
|
||||
sudo: required
|
||||
|
||||
language: go
|
||||
|
||||
os:
|
||||
- osx
|
||||
|
||||
go:
|
||||
- 1.7.3
|
||||
|
||||
before_install:
|
||||
- go get -v -t ./...
|
||||
- brew install mysql
|
||||
- mysql.server start
|
||||
|
||||
install:
|
||||
- mysql -uroot -e 'create database osin;'
|
||||
|
||||
script:
|
||||
- go test -v -race ./...
|
68
vendor/github.com/felipeweb/osin-mysql/README.md
generated
vendored
Normal file
68
vendor/github.com/felipeweb/osin-mysql/README.md
generated
vendored
Normal file
@@ -0,0 +1,68 @@
|
||||
# osin-mysql
|
||||
|
||||
 [](https://godoc.org/github.com/felipeweb/osin-mysql)
|
||||
|
||||
A MySQL storage backend for [osin oauth2](https://github.com/RangelReale/osin).
|
||||
Additional to implementing the `osin.Storage` interface, the `github.com/felipeweb/osin-mysql/storage.Storage` interface defines new methods:
|
||||
|
||||
```
|
||||
// CreateClient stores the client in the database and returns an error, if something went wrong.
|
||||
CreateClient(client osin.Client) error
|
||||
|
||||
// UpdateClient updates the client (identified by its id) and replaces the values with the values of client.
|
||||
// Returns an error if something went wrong.
|
||||
UpdateClient(client osin.Client) error
|
||||
|
||||
// RemoveClient removes a client (identified by id) from the database. Returns an error if something went wrong.
|
||||
RemoveClient(id string) error
|
||||
```
|
||||
|
||||
## Encrypt your tokens
|
||||
|
||||
Unfortunately, the osin library offers little capabilities for storing credentials like access or refresh tokens in a
|
||||
hashed or encrypted way. An attacker could gain access to your database through various attack vectors, steal these
|
||||
tokens and gain, for example, administrative access to your application.
|
||||
|
||||
Please be aware, that this library stores all data as-is and does not perform any sort of encryption or hashing.
|
||||
|
||||
## Usage
|
||||
|
||||
First, install this library with `go get "github.com/felipeweb/osin-mysql"`.
|
||||
|
||||
```go
|
||||
import (
|
||||
"database/sql"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
|
||||
"github.com/felipeweb/osin-mysql"
|
||||
"github.com/RangelReale/osin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
url := "user:password@tcp(host:3306)/dbname?parseTime=true"
|
||||
db, err := sql.Open("mysql", url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
store := mysql.New(db,"osin_")
|
||||
store.CreateSchemas()
|
||||
server := osin.NewServer(osin.NewServerConfig(), store)
|
||||
|
||||
// See the osin documentation for more information
|
||||
// e.g.: server.HandleAuthorizeRequest(resp, r)
|
||||
}
|
||||
```
|
||||
|
||||
## Limitations
|
||||
|
||||
TL;DR `AuthorizeData`'s `Client`'s and `AccessData`'s `UserData` field must be string due to language restrictions or an error will be thrown.
|
||||
|
||||
In osin, Client, AuthorizeData and AccessData have a `UserData` property of type `interface{}`. This does not work well
|
||||
with SQL, because it is not possible to gob decode or unmarshall the data back, since the concrete type is not known.
|
||||
Because osin's storage interface does not support setting the UserData type, **this library tries to convert UserData to string
|
||||
and return it as such.** With this, you could for example gob encode (use e.g. base64 encode for SQL storage type compatibility)
|
||||
the data before passing it to e.g. `FinishAccessRequest` and decode it when needed.
|
||||
|
||||
# 2016-10-23 BREAKING CHANGES
|
||||
- Now `New()` recives a db object and a table prefix as parameter
|
50
vendor/github.com/felipeweb/osin-mysql/doc.go
generated
vendored
Normal file
50
vendor/github.com/felipeweb/osin-mysql/doc.go
generated
vendored
Normal file
@@ -0,0 +1,50 @@
|
||||
/*Package mysql is a storage backend for osin oauth2. Additional to implementing the osin.Storage interface, the github.com/felipeweb/osin-mysql/storage.Storage interface defines new methods:
|
||||
|
||||
// CreateClient stores the client in the database and returns an error, if something went wrong.
|
||||
CreateClient(client osin.Client) error
|
||||
|
||||
// UpdateClient updates the client (identified by its id) and replaces the values with the values of client.
|
||||
// Returns an error if something went wrong.
|
||||
UpdateClient(client osin.Client) error
|
||||
|
||||
// RemoveClient removes a client (identified by id) from the database. Returns an error if something went wrong.
|
||||
RemoveClient(id string) error
|
||||
Encrypt your tokens
|
||||
|
||||
Unfortunately, the osin library offers little capabilities for storing credentials like access or refresh tokens in a hashed or encrypted way. An attacker could gain access to your database through various attack vectors, steal these tokens and gain, for example, administrative access to your application.
|
||||
|
||||
Please be aware, that this library stores all data as-is and does not perform any sort of encryption or hashing.
|
||||
|
||||
Usage
|
||||
|
||||
First, install this library with go get "github.com/felipeweb/osin-mysql".
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
|
||||
"github.com/felipeweb/osin-mysql"
|
||||
"github.com/RangelReale/osin"
|
||||
)
|
||||
|
||||
func main() {
|
||||
url := "user:password@tcp(host:3306)/dbname?parseTime=true"
|
||||
db, err := sql.Open("mysql", url)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
store := mysql.New(db,"osin_")
|
||||
store.CreateSchemas()
|
||||
server := osin.NewServer(osin.NewServerConfig(), store)
|
||||
|
||||
// See the osin documentation for more information
|
||||
// e.g.: server.HandleAuthorizeRequest(resp, r)
|
||||
}
|
||||
Limitations
|
||||
|
||||
TL;DR AuthorizeData's Client's and AccessData's UserData field must be string due to language restrictions or an error will be thrown.
|
||||
|
||||
In osin, Client, AuthorizeData and AccessData have a UserData property of type interface{}. This does not work well with SQL, because it is not possible to gob decode or unmarshall the data back, since the concrete type is not known. Because osin's storage interface does not support setting the UserData type, this library tries to convert UserData to string and return it as such. With this, you could for example gob encode (use e.g. base64 encode for SQL storage type compatibility) the data before passing it to e.g. FinishAccessRequest and decode it when needed.
|
||||
*/
|
||||
package mysql
|
140
vendor/github.com/felipeweb/osin-mysql/examples/simple.go
generated
vendored
Normal file
140
vendor/github.com/felipeweb/osin-mysql/examples/simple.go
generated
vendored
Normal file
@@ -0,0 +1,140 @@
|
||||
package main
|
||||
|
||||
// Open url in browser:
|
||||
// http://localhost:14000/app
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"github.com/RangelReale/osin"
|
||||
"github.com/RangelReale/osin/example"
|
||||
"github.com/felipeweb/osin-mysql"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"net/http"
|
||||
"net/url"
|
||||
)
|
||||
|
||||
func main() {
|
||||
urldb := "root:@tcp(localhost:3306)/osin?parseTime=true"
|
||||
db, err := sql.Open("mysql", urldb)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
store := mysql.New(db, "osin_")
|
||||
err = store.CreateSchemas()
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
cfg := osin.NewServerConfig()
|
||||
cfg.AllowGetAccessRequest = true
|
||||
cfg.AllowClientSecretInParams = true
|
||||
|
||||
server := osin.NewServer(cfg, store)
|
||||
|
||||
// Authorization code endpoint
|
||||
http.HandleFunc("/authorize", func(w http.ResponseWriter, r *http.Request) {
|
||||
resp := server.NewResponse()
|
||||
defer resp.Close()
|
||||
|
||||
if ar := server.HandleAuthorizeRequest(resp, r); ar != nil {
|
||||
if !example.HandleLoginPage(ar, w, r) {
|
||||
return
|
||||
}
|
||||
ar.Authorized = true
|
||||
server.FinishAuthorizeRequest(resp, r, ar)
|
||||
}
|
||||
if resp.IsError && resp.InternalError != nil {
|
||||
fmt.Printf("ERROR: %s\n", resp.InternalError)
|
||||
}
|
||||
osin.OutputJSON(resp, w, r)
|
||||
})
|
||||
|
||||
// Access token endpoint
|
||||
http.HandleFunc("/token", func(w http.ResponseWriter, r *http.Request) {
|
||||
resp := server.NewResponse()
|
||||
defer resp.Close()
|
||||
|
||||
if ar := server.HandleAccessRequest(resp, r); ar != nil {
|
||||
ar.Authorized = true
|
||||
server.FinishAccessRequest(resp, r, ar)
|
||||
}
|
||||
if resp.IsError && resp.InternalError != nil {
|
||||
fmt.Printf("ERROR: %s\n", resp.InternalError)
|
||||
}
|
||||
osin.OutputJSON(resp, w, r)
|
||||
})
|
||||
|
||||
// Information endpoint
|
||||
http.HandleFunc("/info", func(w http.ResponseWriter, r *http.Request) {
|
||||
resp := server.NewResponse()
|
||||
defer resp.Close()
|
||||
|
||||
if ir := server.HandleInfoRequest(resp, r); ir != nil {
|
||||
server.FinishInfoRequest(resp, r, ir)
|
||||
}
|
||||
osin.OutputJSON(resp, w, r)
|
||||
})
|
||||
|
||||
// Application home endpoint
|
||||
http.HandleFunc("/app", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte("<html><body>"))
|
||||
w.Write([]byte(fmt.Sprintf("<a href=\"/authorize?response_type=code&client_id=1234&state=xyz&scope=everything&redirect_uri=%s\">Login</a><br/>", url.QueryEscape("http://localhost:14000/appauth/code"))))
|
||||
w.Write([]byte("</body></html>"))
|
||||
})
|
||||
|
||||
// Application destination - CODE
|
||||
http.HandleFunc("/appauth/code", func(w http.ResponseWriter, r *http.Request) {
|
||||
r.ParseForm()
|
||||
|
||||
code := r.Form.Get("code")
|
||||
|
||||
w.Write([]byte("<html><body>"))
|
||||
w.Write([]byte("APP AUTH - CODE<br/>"))
|
||||
defer w.Write([]byte("</body></html>"))
|
||||
|
||||
if code == "" {
|
||||
w.Write([]byte("Nothing to do"))
|
||||
return
|
||||
}
|
||||
|
||||
jr := make(map[string]interface{})
|
||||
|
||||
// build access code url
|
||||
aurl := fmt.Sprintf("/token?grant_type=authorization_code&client_id=1234&client_secret=aabbccdd&state=xyz&redirect_uri=%s&code=%s",
|
||||
url.QueryEscape("http://localhost:14000/appauth/code"), url.QueryEscape(code))
|
||||
|
||||
// if parse, download and parse json
|
||||
if r.Form.Get("doparse") == "1" {
|
||||
err := example.DownloadAccessToken(fmt.Sprintf("http://localhost:14000%s", aurl),
|
||||
&osin.BasicAuth{"1234", "aabbccdd"}, jr)
|
||||
if err != nil {
|
||||
w.Write([]byte(err.Error()))
|
||||
w.Write([]byte("<br/>"))
|
||||
}
|
||||
}
|
||||
|
||||
// show json error
|
||||
if erd, ok := jr["error"]; ok {
|
||||
w.Write([]byte(fmt.Sprintf("ERROR: %s<br/>\n", erd)))
|
||||
}
|
||||
|
||||
// show json access token
|
||||
if at, ok := jr["access_token"]; ok {
|
||||
w.Write([]byte(fmt.Sprintf("ACCESS TOKEN: %s<br/>\n", at)))
|
||||
}
|
||||
|
||||
w.Write([]byte(fmt.Sprintf("FULL RESULT: %+v<br/>\n", jr)))
|
||||
|
||||
// output links
|
||||
w.Write([]byte(fmt.Sprintf("<a href=\"%s\">Goto Token URL</a><br/>", aurl)))
|
||||
|
||||
cururl := *r.URL
|
||||
curq := cururl.Query()
|
||||
curq.Add("doparse", "1")
|
||||
cururl.RawQuery = curq.Encode()
|
||||
w.Write([]byte(fmt.Sprintf("<a href=\"%s\">Download Token</a><br/>", cururl.String())))
|
||||
})
|
||||
|
||||
http.ListenAndServe(":14000", nil)
|
||||
}
|
363
vendor/github.com/felipeweb/osin-mysql/mysql.go
generated
vendored
Normal file
363
vendor/github.com/felipeweb/osin-mysql/mysql.go
generated
vendored
Normal file
@@ -0,0 +1,363 @@
|
||||
// Package mysql is a osin storage implementation for mysql.
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"log"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/RangelReale/osin"
|
||||
"github.com/ansel1/merry"
|
||||
"github.com/felipeweb/gopher-utils"
|
||||
// driver for mysql db
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
)
|
||||
|
||||
var schemas = []string{`CREATE TABLE IF NOT EXISTS {prefix}client (
|
||||
id varchar(255) BINARY NOT NULL PRIMARY KEY,
|
||||
secret varchar(255) NOT NULL,
|
||||
extra varchar(255) NOT NULL,
|
||||
redirect_uri varchar(255) NOT NULL
|
||||
)`, `CREATE TABLE IF NOT EXISTS {prefix}authorize (
|
||||
client varchar(255) BINARY NOT NULL,
|
||||
code varchar(255) BINARY NOT NULL PRIMARY KEY,
|
||||
expires_in int(10) NOT NULL,
|
||||
scope varchar(255) NOT NULL,
|
||||
redirect_uri varchar(255) NOT NULL,
|
||||
state varchar(255) NOT NULL,
|
||||
extra varchar(255) NOT NULL,
|
||||
created_at timestamp NOT NULL
|
||||
)`, `CREATE TABLE IF NOT EXISTS {prefix}access (
|
||||
client varchar(255) BINARY NOT NULL,
|
||||
authorize varchar(255) BINARY NOT NULL,
|
||||
previous varchar(255) BINARY NOT NULL,
|
||||
access_token varchar(255) BINARY NOT NULL PRIMARY KEY,
|
||||
refresh_token varchar(255) BINARY NOT NULL,
|
||||
expires_in int(10) NOT NULL,
|
||||
scope varchar(255) NOT NULL,
|
||||
redirect_uri varchar(255) NOT NULL,
|
||||
extra varchar(255) NOT NULL,
|
||||
created_at timestamp NOT NULL
|
||||
)`, `CREATE TABLE IF NOT EXISTS {prefix}refresh (
|
||||
token varchar(255) BINARY NOT NULL PRIMARY KEY,
|
||||
access varchar(255) BINARY NOT NULL
|
||||
)`, `CREATE TABLE IF NOT EXISTS {prefix}expires (
|
||||
id int(11) NOT NULL PRIMARY KEY AUTO_INCREMENT,
|
||||
token varchar(255) BINARY NOT NULL,
|
||||
expires_at timestamp NOT NULL,
|
||||
INDEX expires_index (expires_at),
|
||||
INDEX token_expires_index (token)
|
||||
)`,
|
||||
}
|
||||
|
||||
// Storage implements interface "github.com/RangelReale/osin".Storage and interface "github.com/felipeweb/osin-mysql/storage".Storage
|
||||
type Storage struct {
|
||||
db *sql.DB
|
||||
tablePrefix string
|
||||
}
|
||||
|
||||
// New returns a new mysql storage instance.
|
||||
func New(db *sql.DB, tablePrefix string) *Storage {
|
||||
return &Storage{db, tablePrefix}
|
||||
}
|
||||
|
||||
// CreateSchemas creates the schemata, if they do not exist yet in the database. Returns an error if something went wrong.
|
||||
func (s *Storage) CreateSchemas() error {
|
||||
for k, schema := range schemas {
|
||||
schema := strings.Replace(schema, "{prefix}", s.tablePrefix, 4)
|
||||
if _, err := s.db.Exec(schema); err != nil {
|
||||
log.Printf("Error creating schema %d: %s", k, schema)
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Clone the storage if needed. For example, using mgo, you can clone the session with session.Clone
|
||||
// to avoid concurrent access problems.
|
||||
// This is to avoid cloning the connection at each method access.
|
||||
// Can return itself if not a problem.
|
||||
func (s *Storage) Clone() osin.Storage {
|
||||
return s
|
||||
}
|
||||
|
||||
// Close the resources the Storage potentially holds (using Clone for example)
|
||||
func (s *Storage) Close() {
|
||||
}
|
||||
|
||||
// GetClient loads the client by id
|
||||
func (s *Storage) GetClient(id string) (osin.Client, error) {
|
||||
row := s.db.QueryRow(fmt.Sprintf("SELECT id, secret, redirect_uri, extra FROM %sclient WHERE id=?", s.tablePrefix), id)
|
||||
var c osin.DefaultClient
|
||||
var extra string
|
||||
|
||||
if err := row.Scan(&c.Id, &c.Secret, &c.RedirectUri, &extra); err == sql.ErrNoRows {
|
||||
return nil, osin.ErrNotFound
|
||||
} else if err != nil {
|
||||
return nil, merry.Wrap(err)
|
||||
}
|
||||
c.UserData = extra
|
||||
return &c, nil
|
||||
}
|
||||
|
||||
// UpdateClient updates the client (identified by it's id) and replaces the values with the values of client.
|
||||
func (s *Storage) UpdateClient(c osin.Client) error {
|
||||
data := gopher_utils.ToStr(c.GetUserData())
|
||||
|
||||
if _, err := s.db.Exec(fmt.Sprintf("UPDATE %sclient SET secret=?, redirect_uri=?, extra=? WHERE id=?", s.tablePrefix), c.GetSecret(), c.GetRedirectUri(), data, c.GetId()); err != nil {
|
||||
return merry.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateClient stores the client in the database and returns an error, if something went wrong.
|
||||
func (s *Storage) CreateClient(c osin.Client) error {
|
||||
data := gopher_utils.ToStr(c.GetUserData())
|
||||
|
||||
if _, err := s.db.Exec(fmt.Sprintf("INSERT INTO %sclient (id, secret, redirect_uri, extra) VALUES (?, ?, ?, ?)", s.tablePrefix), c.GetId(), c.GetSecret(), c.GetRedirectUri(), data); err != nil {
|
||||
return merry.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveClient removes a client (identified by id) from the database. Returns an error if something went wrong.
|
||||
func (s *Storage) RemoveClient(id string) (err error) {
|
||||
if _, err = s.db.Exec(fmt.Sprintf("DELETE FROM %sclient WHERE id=?", s.tablePrefix), id); err != nil {
|
||||
return merry.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SaveAuthorize saves authorize data.
|
||||
func (s *Storage) SaveAuthorize(data *osin.AuthorizeData) (err error) {
|
||||
extra := gopher_utils.ToStr(data.UserData)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if _, err = s.db.Exec(
|
||||
fmt.Sprintf("INSERT INTO %sauthorize (client, code, expires_in, scope, redirect_uri, state, created_at, extra) VALUES (?, ?, ?, ?, ?, ?, ?, ?)", s.tablePrefix),
|
||||
data.Client.GetId(),
|
||||
data.Code,
|
||||
data.ExpiresIn,
|
||||
data.Scope,
|
||||
data.RedirectUri,
|
||||
data.State,
|
||||
data.CreatedAt,
|
||||
extra,
|
||||
); err != nil {
|
||||
return merry.Wrap(err)
|
||||
}
|
||||
if err = s.AddExpireAtData(data.Code, data.ExpireAt()); err != nil {
|
||||
return merry.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadAuthorize looks up AuthorizeData by a code.
|
||||
// Client information MUST be loaded together.
|
||||
// Optionally can return error if expired.
|
||||
func (s *Storage) LoadAuthorize(code string) (*osin.AuthorizeData, error) {
|
||||
var data osin.AuthorizeData
|
||||
var extra string
|
||||
var cid string
|
||||
if err := s.db.QueryRow(fmt.Sprintf("SELECT client, code, expires_in, scope, redirect_uri, state, created_at, extra FROM %sauthorize WHERE code=? LIMIT 1", s.tablePrefix), code).Scan(&cid, &data.Code, &data.ExpiresIn, &data.Scope, &data.RedirectUri, &data.State, &data.CreatedAt, &extra); err == sql.ErrNoRows {
|
||||
return nil, osin.ErrNotFound
|
||||
} else if err != nil {
|
||||
return nil, merry.Wrap(err)
|
||||
}
|
||||
data.UserData = extra
|
||||
|
||||
c, err := s.GetClient(cid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if data.ExpireAt().Before(time.Now()) {
|
||||
return nil, merry.Errorf("Token expired at %s.", data.ExpireAt().String())
|
||||
}
|
||||
|
||||
data.Client = c
|
||||
return &data, nil
|
||||
}
|
||||
|
||||
// RemoveAuthorize revokes or deletes the authorization code.
|
||||
func (s *Storage) RemoveAuthorize(code string) (err error) {
|
||||
if _, err = s.db.Exec(fmt.Sprintf("DELETE FROM %sauthorize WHERE code=?", s.tablePrefix), code); err != nil {
|
||||
return merry.Wrap(err)
|
||||
}
|
||||
if err = s.RemoveExpireAtData(code); err != nil {
|
||||
return merry.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// SaveAccess writes AccessData.
|
||||
// If RefreshToken is not blank, it must save in a way that can be loaded using LoadRefresh.
|
||||
func (s *Storage) SaveAccess(data *osin.AccessData) (err error) {
|
||||
prev := ""
|
||||
authorizeData := &osin.AuthorizeData{}
|
||||
|
||||
if data.AccessData != nil {
|
||||
prev = data.AccessData.AccessToken
|
||||
}
|
||||
|
||||
if data.AuthorizeData != nil {
|
||||
authorizeData = data.AuthorizeData
|
||||
}
|
||||
|
||||
extra := gopher_utils.ToStr(data.UserData)
|
||||
|
||||
tx, err := s.db.Begin()
|
||||
if err != nil {
|
||||
return merry.Wrap(err)
|
||||
}
|
||||
|
||||
if data.RefreshToken != "" {
|
||||
if err := s.saveRefresh(tx, data.RefreshToken, data.AccessToken); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
if data.Client == nil {
|
||||
return merry.New("data.Client must not be nil")
|
||||
}
|
||||
|
||||
_, err = tx.Exec(fmt.Sprintf("INSERT INTO %saccess (client, authorize, previous, access_token, refresh_token, expires_in, scope, redirect_uri, created_at, extra) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)", s.tablePrefix), data.Client.GetId(), authorizeData.Code, prev, data.AccessToken, data.RefreshToken, data.ExpiresIn, data.Scope, data.RedirectUri, data.CreatedAt, extra)
|
||||
if err != nil {
|
||||
if rbe := tx.Rollback(); rbe != nil {
|
||||
return merry.Wrap(rbe)
|
||||
}
|
||||
return merry.Wrap(err)
|
||||
}
|
||||
|
||||
if err = s.AddExpireAtData(data.AccessToken, data.ExpireAt()); err != nil {
|
||||
return merry.Wrap(err)
|
||||
}
|
||||
if err = tx.Commit(); err != nil {
|
||||
return merry.Wrap(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadAccess retrieves access data by token. Client information MUST be loaded together.
|
||||
// AuthorizeData and AccessData DON'T NEED to be loaded if not easily available.
|
||||
// Optionally can return error if expired.
|
||||
func (s *Storage) LoadAccess(code string) (*osin.AccessData, error) {
|
||||
var extra, cid, prevAccessToken, authorizeCode string
|
||||
var result osin.AccessData
|
||||
|
||||
if err := s.db.QueryRow(
|
||||
fmt.Sprintf("SELECT client, authorize, previous, access_token, refresh_token, expires_in, scope, redirect_uri, created_at, extra FROM %saccess WHERE access_token=? LIMIT 1", s.tablePrefix),
|
||||
code,
|
||||
).Scan(
|
||||
&cid,
|
||||
&authorizeCode,
|
||||
&prevAccessToken,
|
||||
&result.AccessToken,
|
||||
&result.RefreshToken,
|
||||
&result.ExpiresIn,
|
||||
&result.Scope,
|
||||
&result.RedirectUri,
|
||||
&result.CreatedAt,
|
||||
&extra,
|
||||
); err == sql.ErrNoRows {
|
||||
return nil, osin.ErrNotFound
|
||||
} else if err != nil {
|
||||
return nil, merry.Wrap(err)
|
||||
}
|
||||
|
||||
result.UserData = extra
|
||||
client, err := s.GetClient(cid)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
result.Client = client
|
||||
result.AuthorizeData, _ = s.LoadAuthorize(authorizeCode)
|
||||
prevAccess, _ := s.LoadAccess(prevAccessToken)
|
||||
result.AccessData = prevAccess
|
||||
return &result, nil
|
||||
}
|
||||
|
||||
// RemoveAccess revokes or deletes an AccessData.
|
||||
func (s *Storage) RemoveAccess(code string) (err error) {
|
||||
if _, err = s.db.Exec(fmt.Sprintf("DELETE FROM %saccess WHERE access_token=?", s.tablePrefix), code); err != nil {
|
||||
return merry.Wrap(err)
|
||||
}
|
||||
if err = s.RemoveExpireAtData(code); err != nil {
|
||||
return merry.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// LoadRefresh retrieves refresh AccessData. Client information MUST be loaded together.
|
||||
// AuthorizeData and AccessData DON'T NEED to be loaded if not easily available.
|
||||
// Optionally can return error if expired.
|
||||
func (s *Storage) LoadRefresh(code string) (*osin.AccessData, error) {
|
||||
row := s.db.QueryRow(fmt.Sprintf("SELECT access FROM %srefresh WHERE token=? LIMIT 1", s.tablePrefix), code)
|
||||
var access string
|
||||
if err := row.Scan(&access); err == sql.ErrNoRows {
|
||||
return nil, osin.ErrNotFound
|
||||
} else if err != nil {
|
||||
return nil, merry.Wrap(err)
|
||||
}
|
||||
return s.LoadAccess(access)
|
||||
}
|
||||
|
||||
// RemoveRefresh revokes or deletes refresh AccessData.
|
||||
func (s *Storage) RemoveRefresh(code string) error {
|
||||
_, err := s.db.Exec(fmt.Sprintf("DELETE FROM %srefresh WHERE token=?", s.tablePrefix), code)
|
||||
if err != nil {
|
||||
return merry.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// CreateClientWithInformation Makes easy to create a osin.DefaultClient
|
||||
func (s *Storage) CreateClientWithInformation(id string, secret string, redirectURI string, userData interface{}) osin.Client {
|
||||
return &osin.DefaultClient{
|
||||
Id: id,
|
||||
Secret: secret,
|
||||
RedirectUri: redirectURI,
|
||||
UserData: userData,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Storage) saveRefresh(tx *sql.Tx, refresh, access string) (err error) {
|
||||
_, err = tx.Exec(fmt.Sprintf("INSERT INTO %srefresh (token, access) VALUES (?, ?)", s.tablePrefix), refresh, access)
|
||||
if err != nil {
|
||||
if rbe := tx.Rollback(); rbe != nil {
|
||||
return merry.Wrap(rbe)
|
||||
}
|
||||
return merry.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// AddExpireAtData add info in expires table
|
||||
func (s *Storage) AddExpireAtData(code string, expireAt time.Time) error {
|
||||
if _, err := s.db.Exec(
|
||||
fmt.Sprintf("INSERT INTO %sexpires(token, expires_at) VALUES(?, ?)", s.tablePrefix),
|
||||
code,
|
||||
expireAt,
|
||||
); err != nil {
|
||||
return merry.Wrap(err)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// RemoveExpireAtData remove info in expires table
|
||||
func (s *Storage) RemoveExpireAtData(code string) error {
|
||||
if _, err := s.db.Exec(
|
||||
fmt.Sprintf("DELETE FROM %sexpires WHERE token=?", s.tablePrefix),
|
||||
code,
|
||||
); err != nil {
|
||||
return merry.Wrap(err)
|
||||
}
|
||||
return nil
|
||||
}
|
243
vendor/github.com/felipeweb/osin-mysql/mysql_test.go
generated
vendored
Normal file
243
vendor/github.com/felipeweb/osin-mysql/mysql_test.go
generated
vendored
Normal file
@@ -0,0 +1,243 @@
|
||||
package mysql
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"log"
|
||||
"os"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/RangelReale/osin"
|
||||
_ "github.com/go-sql-driver/mysql"
|
||||
"github.com/pborman/uuid"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
var db *sql.DB
|
||||
var store *Storage
|
||||
var userDataMock = "bar"
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
var err error
|
||||
db, err = sql.Open("mysql", "root:@tcp(localhost:3306)/osin?parseTime=true")
|
||||
if err != nil {
|
||||
log.Fatalf("Could not open connect to database: %s", err)
|
||||
|
||||
}
|
||||
err = db.Ping()
|
||||
|
||||
if err != nil {
|
||||
log.Fatalf("Could not connect to database: %s", err)
|
||||
}
|
||||
|
||||
store = New(db, "osin_")
|
||||
if err = store.CreateSchemas(); err != nil {
|
||||
log.Fatalf("Could not ping database: %v", err)
|
||||
}
|
||||
|
||||
retCode := m.Run()
|
||||
|
||||
os.Exit(retCode)
|
||||
}
|
||||
|
||||
func TestClientOperations(t *testing.T) {
|
||||
create := &osin.DefaultClient{Id: "1", Secret: "secret", RedirectUri: "http://localhost/", UserData: ""}
|
||||
createClient(t, *store, create)
|
||||
getClient(t, *store, create)
|
||||
}
|
||||
|
||||
func TestAuthorizeOperations(t *testing.T) {
|
||||
client := &osin.DefaultClient{Id: "2", Secret: "secret", RedirectUri: "http://localhost/", UserData: ""}
|
||||
createClient(t, *store, client)
|
||||
|
||||
for _, authorize := range []*osin.AuthorizeData{
|
||||
{
|
||||
Client: client,
|
||||
Code: uuid.New(),
|
||||
ExpiresIn: int32(600),
|
||||
Scope: "scope",
|
||||
RedirectUri: "http://localhost/",
|
||||
State: "state",
|
||||
CreatedAt: time.Now().Round(time.Second),
|
||||
UserData: userDataMock,
|
||||
},
|
||||
} {
|
||||
// Test save
|
||||
require.Nil(t, store.SaveAuthorize(authorize))
|
||||
|
||||
// Test fetch
|
||||
_, err := store.LoadAuthorize(authorize.Code)
|
||||
require.Nil(t, err)
|
||||
require.Equal(t, authorize.CreatedAt.Unix(), authorize.CreatedAt.Unix())
|
||||
|
||||
// Test remove
|
||||
require.Nil(t, store.RemoveAuthorize(authorize.Code))
|
||||
_, err = store.LoadAuthorize(authorize.Code)
|
||||
require.NotNil(t, err)
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
func TestStoreFailsOnInvalidUserData(t *testing.T) {
|
||||
client := &osin.DefaultClient{Id: "3", Secret: "secret", RedirectUri: "http://localhost/", UserData: ""}
|
||||
authorize := &osin.AuthorizeData{
|
||||
Client: client,
|
||||
Code: uuid.New(),
|
||||
ExpiresIn: int32(60),
|
||||
Scope: "scope",
|
||||
RedirectUri: "http://localhost/",
|
||||
State: "state",
|
||||
CreatedAt: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
UserData: struct{ foo string }{"bar"},
|
||||
}
|
||||
access := &osin.AccessData{
|
||||
Client: client,
|
||||
AuthorizeData: authorize,
|
||||
AccessData: nil,
|
||||
AccessToken: uuid.New(),
|
||||
RefreshToken: uuid.New(),
|
||||
ExpiresIn: int32(60),
|
||||
Scope: "scope",
|
||||
RedirectUri: "https://localhost/",
|
||||
CreatedAt: time.Date(2009, time.November, 10, 23, 0, 0, 0, time.UTC),
|
||||
UserData: struct{ foo string }{"bar"},
|
||||
}
|
||||
assert.Nil(t, store.SaveAuthorize(authorize))
|
||||
assert.Nil(t, store.SaveAccess(access))
|
||||
}
|
||||
|
||||
func TestAccessOperations(t *testing.T) {
|
||||
client := &osin.DefaultClient{Id: "3", Secret: "secret", RedirectUri: "http://localhost/", UserData: ""}
|
||||
authorize := &osin.AuthorizeData{
|
||||
Client: client,
|
||||
Code: uuid.New(),
|
||||
ExpiresIn: int32(60),
|
||||
Scope: "scope",
|
||||
RedirectUri: "http://localhost/",
|
||||
State: "state",
|
||||
CreatedAt: time.Now().Round(time.Second),
|
||||
UserData: userDataMock,
|
||||
}
|
||||
nestedAccess := &osin.AccessData{
|
||||
Client: client,
|
||||
AuthorizeData: authorize,
|
||||
AccessData: nil,
|
||||
AccessToken: uuid.New(),
|
||||
RefreshToken: uuid.New(),
|
||||
ExpiresIn: int32(60),
|
||||
Scope: "scope",
|
||||
RedirectUri: "https://localhost/",
|
||||
CreatedAt: time.Now().Round(time.Second),
|
||||
UserData: userDataMock,
|
||||
}
|
||||
access := &osin.AccessData{
|
||||
Client: client,
|
||||
AuthorizeData: authorize,
|
||||
AccessData: nestedAccess,
|
||||
AccessToken: uuid.New(),
|
||||
RefreshToken: uuid.New(),
|
||||
ExpiresIn: int32(60),
|
||||
Scope: "scope",
|
||||
RedirectUri: "https://localhost/",
|
||||
CreatedAt: time.Now().Round(time.Second),
|
||||
UserData: userDataMock,
|
||||
}
|
||||
|
||||
require.Nil(t, store.SaveAuthorize(authorize))
|
||||
require.Nil(t, store.SaveAccess(nestedAccess))
|
||||
require.Nil(t, store.SaveAccess(access))
|
||||
|
||||
_, err := store.LoadAccess(access.AccessToken)
|
||||
require.NotNil(t, err)
|
||||
|
||||
require.Nil(t, store.RemoveAuthorize(authorize.Code))
|
||||
_, err = store.LoadAccess(access.AccessToken)
|
||||
require.NotNil(t, err)
|
||||
|
||||
require.Nil(t, store.RemoveAccess(nestedAccess.AccessToken))
|
||||
_, err = store.LoadAccess(access.AccessToken)
|
||||
require.NotNil(t, err)
|
||||
|
||||
require.Nil(t, store.RemoveAccess(access.AccessToken))
|
||||
_, err = store.LoadAccess(access.AccessToken)
|
||||
require.NotNil(t, err)
|
||||
|
||||
require.Nil(t, store.RemoveAuthorize(authorize.Code))
|
||||
}
|
||||
|
||||
func TestRefreshOperations(t *testing.T) {
|
||||
client := &osin.DefaultClient{Id: "4", Secret: "secret", RedirectUri: "http://localhost/", UserData: ""}
|
||||
type test struct {
|
||||
access *osin.AccessData
|
||||
}
|
||||
|
||||
for k, c := range []*test{
|
||||
{
|
||||
access: &osin.AccessData{
|
||||
Client: client,
|
||||
AuthorizeData: &osin.AuthorizeData{
|
||||
Client: client,
|
||||
Code: uuid.New(),
|
||||
ExpiresIn: int32(60),
|
||||
Scope: "scope",
|
||||
RedirectUri: "http://localhost/",
|
||||
State: "state",
|
||||
CreatedAt: time.Now().Round(time.Second),
|
||||
UserData: userDataMock,
|
||||
},
|
||||
AccessData: nil,
|
||||
AccessToken: uuid.New(),
|
||||
RefreshToken: uuid.New(),
|
||||
ExpiresIn: int32(60),
|
||||
Scope: "scope",
|
||||
RedirectUri: "https://localhost/",
|
||||
CreatedAt: time.Now().Round(time.Second),
|
||||
UserData: userDataMock,
|
||||
},
|
||||
},
|
||||
} {
|
||||
|
||||
_, err := store.LoadRefresh(c.access.RefreshToken)
|
||||
require.NotNil(t, err)
|
||||
|
||||
require.Nil(t, store.RemoveRefresh(c.access.RefreshToken))
|
||||
_, err = store.LoadRefresh(c.access.RefreshToken)
|
||||
|
||||
require.NotNil(t, err, "Case %d", k)
|
||||
require.Nil(t, store.RemoveAccess(c.access.AccessToken), "Case %d", k)
|
||||
require.Nil(t, store.SaveAccess(c.access), "Case %d", k)
|
||||
|
||||
_, err = store.LoadRefresh(c.access.RefreshToken)
|
||||
require.NotNil(t, err, "Case %d", k)
|
||||
|
||||
require.Nil(t, store.RemoveAccess(c.access.AccessToken), "Case %d", k)
|
||||
_, err = store.LoadRefresh(c.access.RefreshToken)
|
||||
require.NotNil(t, err, "Case %d", k)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
type ts struct{}
|
||||
|
||||
func (s *ts) String() string {
|
||||
return "foo"
|
||||
}
|
||||
|
||||
func TestCreateClientWithInformation(t *testing.T) {
|
||||
res := store.CreateClientWithInformation("1", "123", "http://test.com/redirect", "data")
|
||||
assert.Equal(t, "1", res.GetId())
|
||||
assert.Equal(t, "123", res.GetSecret())
|
||||
assert.Equal(t, "http://test.com/redirect", res.GetRedirectUri())
|
||||
assert.Equal(t, "data", res.GetUserData())
|
||||
}
|
||||
|
||||
func getClient(t *testing.T, store Storage, set osin.Client) {
|
||||
client, err := store.GetClient(set.GetId())
|
||||
require.Nil(t, err)
|
||||
require.EqualValues(t, set, client)
|
||||
}
|
||||
|
||||
func createClient(t *testing.T, store Storage, set osin.Client) {
|
||||
require.Nil(t, store.CreateClient(set))
|
||||
}
|
19
vendor/github.com/felipeweb/osin-mysql/storage/storage.go
generated
vendored
Normal file
19
vendor/github.com/felipeweb/osin-mysql/storage/storage.go
generated
vendored
Normal file
@@ -0,0 +1,19 @@
|
||||
// Package storage defines an interface, which all osin-storage implementations are going to support.
|
||||
package storage
|
||||
|
||||
import "github.com/RangelReale/osin"
|
||||
|
||||
// Storage extends github.com/RangelReale/osin.Storage with create, update and delete methods for clients.
|
||||
type Storage interface {
|
||||
osin.Storage
|
||||
|
||||
// CreateClient stores the client in the database and returns an error, if something went wrong.
|
||||
CreateClient(client osin.Client) error
|
||||
|
||||
// UpdateClient updates the client (identified by it's id) and replaces the values with the values of client.
|
||||
// Returns an error if something went wrong.
|
||||
UpdateClient(client osin.Client) error
|
||||
|
||||
// RemoveClient removes a client (identified by id) from the database. Returns an error if something went wrong.
|
||||
RemoveClient(id string) error
|
||||
}
|
Reference in New Issue
Block a user