replace zxq.co/ripple/hanayo

This commit is contained in:
Alicia
2019-02-23 13:29:15 +00:00
commit c3d206c173
5871 changed files with 1353715 additions and 0 deletions

74
vendor/github.com/felipeweb/osin-mysql/.gitignore generated vendored Normal file
View 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
View 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
View File

@@ -0,0 +1,68 @@
# osin-mysql
![Travis](https://travis-ci.org/felipeweb/osin-mysql.svg?branch=master) [![GoDoc](https://godoc.org/github.com/felipeweb/osin-mysql?status.svg)](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
View 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

View 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
View 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
View 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))
}

View 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
}