neowolves/auth-server/server.go

141 lines
3.8 KiB
Go

package main
import (
"context"
"github.com/nspcc-dev/neo-go/pkg/rpcclient"
"github.com/nspcc-dev/neo-go/pkg/rpcclient/actor"
"github.com/nspcc-dev/neo-go/pkg/util"
"github.com/nspcc-dev/neo-go/pkg/wallet"
"github.com/go-oauth2/oauth2/v4"
"github.com/go-oauth2/oauth2/v4/errors"
"github.com/go-oauth2/oauth2/v4/manage"
"github.com/go-oauth2/oauth2/v4/models"
"github.com/go-oauth2/oauth2/v4/server"
"github.com/go-oauth2/oauth2/v4/store"
"log"
"log/slog"
"net/http"
)
type IBlockchainStorage interface {
GetByID(ctx context.Context, id string) (oauth2.ClientInfo, error) // read
Set(id string, cli oauth2.ClientInfo) (err error) // create and update
Delete(id string) (err error) // delete
CheckPassword(id string, secret util.Uint256) (bool, error) // CheckUser
}
type BlockchainStorage struct {
contract *Contract
}
func NewBlockchainStorage(actor Actor, hash util.Uint160) *BlockchainStorage {
return &BlockchainStorage{contract: New(actor, hash)}
}
func (storage BlockchainStorage) Delete(id string) (err error) {
// how to use hash and ValidUntilBlock?
_, _, err = storage.contract.DeleteUser(id)
return err
}
func (storage BlockchainStorage) CheckPassword(id string, secret util.Uint256) (bool, error) {
_, err := storage.contract.CheckUser(id, secret)
if err == nil {
return true, nil
}
if err.Error() == "Password hashes does not match" {
return false, nil
}
return false, err
}
func main() {
manager := manage.NewDefaultManager()
manager.SetAuthorizeCodeTokenCfg(manage.DefaultAuthorizeCodeTokenCfg)
// contract integration
fileWallet, _ := wallet.NewWalletFromFile("somewhere")
defer fileWallet.Close()
rpcClient, _ := rpcclient.New(context.Background(), "url", rpcclient.Options{})
rpcActor, _ := actor.NewSimple(rpcClient, fileWallet.Accounts[0])
// token memory store
// todo: Implement blockchain store
manager.MustTokenStorage(store.NewMemoryTokenStore())
// client memory store
// todo: Implement blockchain store
clientStore := store.NewClientStore()
manager.MapClientStorage(clientStore)
srv := server.NewDefaultServer(manager)
srv.SetAllowGetAccessRequest(true)
srv.SetClientInfoHandler(server.ClientFormHandler)
manager.SetRefreshTokenCfg(manage.DefaultRefreshTokenCfg)
srv.SetInternalErrorHandler(func(err error) (re *errors.Response) {
log.Println("Internal Error:", err.Error())
return
})
srv.SetResponseErrorHandler(func(re *errors.Response) {
log.Println("Response Error:", re.Error.Error())
})
http.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
srv.HandleTokenRequest(w, r)
})
http.HandleFunc("/register", func(writer http.ResponseWriter, request *http.Request) {
id := request.Header.Get("client_id")
secret := request.Header.Get("client_secret")
// check whether client exists
_, err := clientStore.GetByID(context.Background(), id)
if err == nil {
slog.Warn("Client with id " + id + "already exists.")
writer.WriteHeader(http.StatusBadRequest)
return
}
// add client's credentials to blockchain
err = clientStore.Set(id, &models.Client{
ID: id,
Secret: secret,
})
if err != nil {
slog.Error("Failed to register user with id "+id+".", err)
writer.WriteHeader(http.StatusInternalServerError)
return
}
writer.WriteHeader(http.StatusOK)
})
// for tests
http.HandleFunc("/protected", validateToken(func(w http.ResponseWriter, r *http.Request) {
w.Write([]byte("Hello, I'm protected"))
}, srv))
log.Fatal(http.ListenAndServe(":9096", nil))
}
func validateToken(f http.HandlerFunc, srv *server.Server) http.HandlerFunc {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
_, err := srv.ValidationBearerToken(r)
if err != nil {
http.Error(w, err.Error(), http.StatusBadRequest)
return
}
f.ServeHTTP(w, r)
})
}