mirror of
https://github.com/xslasd/x-oidc.git
synced 2025-10-06 00:16:54 +08:00
edit README.md
add NOTICE file Naming of repair methods
This commit is contained in:
10
NOTICE
Normal file
10
NOTICE
Normal file
@@ -0,0 +1,10 @@
|
|||||||
|
xslasd/x-oidc
|
||||||
|
Copyright 2023 xslasd
|
||||||
|
This product includes software developed by the Apache Software Foundation (http://www.apache.org/).
|
||||||
|
|
||||||
|
This product includes software developed by go-jose (github.com/go-jose/go-jose/v3).
|
||||||
|
This product includes software developed by google/uuid (github.com/google/uuid).
|
||||||
|
|
||||||
|
This project referred to the redesign and implementation of interface functions for zitadel/oidc.
|
||||||
|
|
||||||
|
The above code files or parts of them are licensed under the Apache 2.0 License and are subject to the terms and conditions of the Apache 2.0 License.
|
@@ -21,12 +21,14 @@ op.go definition and implementation of an OIDC OpenID Provider (server)
|
|||||||
|
|
||||||
## Third-party Library
|
## Third-party Library
|
||||||
The library primarily depends on the third-party library "go-jose/v3".
|
The library primarily depends on the third-party library "go-jose/v3".
|
||||||
The HTTP processing section uses an interface-based approach (with net/http being the default), which can be extended as needed.
|
The HTTP processing section uses an interface-based approach , which can be extended as needed.
|
||||||
|
When starting OP, implement Config.OpenIDWrapper. By default, github. com/xslass/x-oidc/example/server/httpwrapper can be used. Implementation based on net/HTTP.
|
||||||
```
|
```
|
||||||
github.com/go-jose/go-jose/v3 v3.0.0
|
github.com/go-jose/go-jose/v3 v3.0.0
|
||||||
github.com/google/uuid v1.3.0
|
github.com/google/uuid v1.3.0
|
||||||
golang.org/x/text v0.9.0
|
golang.org/x/text v0.9.0
|
||||||
```
|
```
|
||||||
|
Special thanks to [zitadel/oidc](https://github.com/zitadel/oidc). This project referred to the redesign and implementation of interface functions for zitadel/oidc.
|
||||||
## Contributors
|
## Contributors
|
||||||
|
|
||||||
<a href="https://github.com/xslasd/x-oidc/graphs/contributors">
|
<a href="https://github.com/xslasd/x-oidc/graphs/contributors">
|
||||||
|
10
config.go
10
config.go
@@ -1,13 +1,13 @@
|
|||||||
package oidc
|
package oidc
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"github.com/xslasd/x-oidc/crypto"
|
|
||||||
"github.com/xslasd/x-oidc/storage"
|
"github.com/xslasd/x-oidc/storage"
|
||||||
|
"github.com/xslasd/x-oidc/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
Issuer string
|
Issuer string
|
||||||
Crypto crypto.JWTCertifier
|
Crypto util.JWTCertifier
|
||||||
Handler OpenIDHandler
|
OpenIDWrapper OpenIDWrapper
|
||||||
Storage storage.IStorage
|
Storage storage.IStorage
|
||||||
}
|
}
|
||||||
|
@@ -1,69 +0,0 @@
|
|||||||
package crypto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/aes"
|
|
||||||
"crypto/cipher"
|
|
||||||
"crypto/rand"
|
|
||||||
"encoding/base64"
|
|
||||||
"errors"
|
|
||||||
"io"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ErrCipherTextBlockSize = errors.New("ciphertext block size is too short")
|
|
||||||
|
|
||||||
func EncryptAES(data string, key string) (string, error) {
|
|
||||||
encrypted, err := EncryptBytesAES([]byte(data), key)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
|
|
||||||
return base64.RawURLEncoding.EncodeToString(encrypted), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func EncryptBytesAES(plainText []byte, key string) ([]byte, error) {
|
|
||||||
block, err := aes.NewCipher([]byte(key))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
cipherText := make([]byte, aes.BlockSize+len(plainText))
|
|
||||||
iv := cipherText[:aes.BlockSize]
|
|
||||||
if _, err = io.ReadFull(rand.Reader, iv); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
stream := cipher.NewCFBEncrypter(block, iv)
|
|
||||||
stream.XORKeyStream(cipherText[aes.BlockSize:], plainText)
|
|
||||||
|
|
||||||
return cipherText, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DecryptAES(data string, key string) (string, error) {
|
|
||||||
text, err := base64.RawURLEncoding.DecodeString(data)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
decrypted, err := DecryptBytesAES(text, key)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return string(decrypted), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func DecryptBytesAES(cipherText []byte, key string) ([]byte, error) {
|
|
||||||
block, err := aes.NewCipher([]byte(key))
|
|
||||||
if err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
|
|
||||||
if len(cipherText) < aes.BlockSize {
|
|
||||||
return nil, ErrCipherTextBlockSize
|
|
||||||
}
|
|
||||||
iv := cipherText[:aes.BlockSize]
|
|
||||||
cipherText = cipherText[aes.BlockSize:]
|
|
||||||
|
|
||||||
stream := cipher.NewCFBDecrypter(block, iv)
|
|
||||||
stream.XORKeyStream(cipherText, cipherText)
|
|
||||||
|
|
||||||
return cipherText, err
|
|
||||||
}
|
|
@@ -1,44 +0,0 @@
|
|||||||
package crypto
|
|
||||||
|
|
||||||
import (
|
|
||||||
"crypto/sha256"
|
|
||||||
"crypto/sha512"
|
|
||||||
"encoding/base64"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"github.com/go-jose/go-jose/v3"
|
|
||||||
"hash"
|
|
||||||
)
|
|
||||||
|
|
||||||
var ErrUnsupportedAlgorithm = errors.New("unsupported signing algorithm")
|
|
||||||
|
|
||||||
func GetHashAlgorithm(sigAlgorithm jose.SignatureAlgorithm) (hash.Hash, error) {
|
|
||||||
switch sigAlgorithm {
|
|
||||||
case jose.RS256, jose.ES256, jose.PS256, jose.HS256:
|
|
||||||
return sha256.New(), nil
|
|
||||||
case jose.RS384, jose.ES384, jose.PS384, jose.HS384:
|
|
||||||
return sha512.New384(), nil
|
|
||||||
case jose.RS512, jose.ES512, jose.PS512, jose.HS512:
|
|
||||||
return sha512.New(), nil
|
|
||||||
default:
|
|
||||||
return nil, fmt.Errorf("%w: %q", ErrUnsupportedAlgorithm, sigAlgorithm)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
func ClaimHash(claim string, sigAlgorithm jose.SignatureAlgorithm) (string, error) {
|
|
||||||
hash, err := GetHashAlgorithm(sigAlgorithm)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return HashString(hash, claim, true), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func HashString(hash hash.Hash, s string, firstHalf bool) string {
|
|
||||||
hash.Write([]byte(s))
|
|
||||||
size := hash.Size()
|
|
||||||
if firstHalf {
|
|
||||||
size = size / 2
|
|
||||||
}
|
|
||||||
sum := hash.Sum(nil)[:size]
|
|
||||||
return base64.RawURLEncoding.EncodeToString(sum)
|
|
||||||
}
|
|
@@ -53,6 +53,7 @@ var (
|
|||||||
UnauthorizedClientGrantType = New(1031, UnsupportedGrantTypeErrorType, "The grantType '%s' unsupported", "")
|
UnauthorizedClientGrantType = New(1031, UnsupportedGrantTypeErrorType, "The grantType '%s' unsupported", "")
|
||||||
AuthReqNotDone = New(1032, InvalidRequestErrorType, "Unfortunately, the user may be not logged in and/or additional interaction is required.", "")
|
AuthReqNotDone = New(1032, InvalidRequestErrorType, "Unfortunately, the user may be not logged in and/or additional interaction is required.", "")
|
||||||
|
|
||||||
PublicKeyInvalid = New(1050, ServerErrorErrorType, "failed to decode PEM block containing public key", "")
|
PublicKeyInvalid = New(1050, ServerErrorErrorType, "failed to decode PEM block containing public key", "")
|
||||||
PrivateKeyInvalid = New(1051, ServerErrorErrorType, "failed to decode PEM block containing private key", "")
|
PrivateKeyInvalid = New(1051, ServerErrorErrorType, "failed to decode PEM block containing private key", "")
|
||||||
|
AlgorithmUnsupported = New(1052, ServerErrorErrorType, "unsupported jose signing algorithm: %s", "")
|
||||||
)
|
)
|
||||||
|
@@ -1,4 +1,4 @@
|
|||||||
package handler
|
package httpwrapper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
@@ -15,20 +15,20 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
type HttpHandler struct {
|
type HttpWrapper struct {
|
||||||
handler *http.ServeMux
|
handler *http.ServeMux
|
||||||
addr string
|
addr string
|
||||||
logger log.Logger
|
logger log.Logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewHttpHandler(addr string) *HttpHandler {
|
func NewHttpHandler(addr string) *HttpWrapper {
|
||||||
return &HttpHandler{handler: http.DefaultServeMux, addr: addr}
|
return &HttpWrapper{handler: http.DefaultServeMux, addr: addr}
|
||||||
}
|
}
|
||||||
func (h *HttpHandler) SetLogger(logger log.Logger) {
|
func (h *HttpWrapper) SetLogger(logger log.Logger) {
|
||||||
h.logger = logger
|
h.logger = logger
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpHandler) ListenAndServe() error {
|
func (h *HttpWrapper) ListenAndServe() error {
|
||||||
h.login()
|
h.login()
|
||||||
var err error
|
var err error
|
||||||
srv := &http.Server{
|
srv := &http.Server{
|
||||||
@@ -60,7 +60,7 @@ func (h *HttpHandler) ListenAndServe() error {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpHandler) DiscoveryJWKs(jwksEndpoint string, handler func() (*jose.JSONWebKeySet, error)) {
|
func (h *HttpWrapper) DiscoveryJWKs(jwksEndpoint string, handler func() (*jose.JSONWebKeySet, error)) {
|
||||||
h.handler.HandleFunc(jwksEndpoint, func(w http.ResponseWriter, r *http.Request) {
|
h.handler.HandleFunc(jwksEndpoint, func(w http.ResponseWriter, r *http.Request) {
|
||||||
data, err := handler()
|
data, err := handler()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -74,7 +74,7 @@ func (h *HttpHandler) DiscoveryJWKs(jwksEndpoint string, handler func() (*jose.J
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpHandler) DiscoveryConfig(discoveryEndpoint string, handler func(req *x_oidc.DiscoveryConfigReq) *model.DiscoveryConfiguration) {
|
func (h *HttpWrapper) DiscoveryConfig(discoveryEndpoint string, handler func(req *x_oidc.DiscoveryConfigReq) *model.DiscoveryConfiguration) {
|
||||||
h.handler.HandleFunc(discoveryEndpoint, func(w http.ResponseWriter, r *http.Request) {
|
h.handler.HandleFunc(discoveryEndpoint, func(w http.ResponseWriter, r *http.Request) {
|
||||||
data := handler(&x_oidc.DiscoveryConfigReq{
|
data := handler(&x_oidc.DiscoveryConfigReq{
|
||||||
RegistrationEndpoint: "",
|
RegistrationEndpoint: "",
|
||||||
@@ -88,7 +88,7 @@ func (h *HttpHandler) DiscoveryConfig(discoveryEndpoint string, handler func(req
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpHandler) Authorize(authorizationEndpoint string, handler func(ctx context.Context, req *x_oidc.AuthRequestReq) (string, error)) {
|
func (h *HttpWrapper) Authorize(authorizationEndpoint string, handler func(ctx context.Context, req *x_oidc.AuthRequestReq) (string, error)) {
|
||||||
h.handler.HandleFunc(authorizationEndpoint, func(w http.ResponseWriter, r *http.Request) {
|
h.handler.HandleFunc(authorizationEndpoint, func(w http.ResponseWriter, r *http.Request) {
|
||||||
var authRequestReq x_oidc.AuthRequestReq
|
var authRequestReq x_oidc.AuthRequestReq
|
||||||
if r.Method == "GET" {
|
if r.Method == "GET" {
|
||||||
@@ -136,7 +136,7 @@ func (h *HttpHandler) Authorize(authorizationEndpoint string, handler func(ctx c
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpHandler) EndSession(endSessionEndpoint string, handler func(ctx context.Context, req *x_oidc.EndSessionReq) (string, error)) {
|
func (h *HttpWrapper) EndSession(endSessionEndpoint string, handler func(ctx context.Context, req *x_oidc.EndSessionReq) (string, error)) {
|
||||||
h.handler.HandleFunc(endSessionEndpoint, func(w http.ResponseWriter, r *http.Request) {
|
h.handler.HandleFunc(endSessionEndpoint, func(w http.ResponseWriter, r *http.Request) {
|
||||||
var endSessionReq x_oidc.EndSessionReq
|
var endSessionReq x_oidc.EndSessionReq
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
@@ -168,7 +168,7 @@ func (h *HttpHandler) EndSession(endSessionEndpoint string, handler func(ctx con
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpHandler) Introspect(introspectionEndpoint string, handler func(ctx context.Context, req *x_oidc.IntrospectionReq, r *http.Request) (*model.IntrospectionModel, error)) {
|
func (h *HttpWrapper) Introspect(introspectionEndpoint string, handler func(ctx context.Context, req *x_oidc.IntrospectionReq, r *http.Request) (*model.IntrospectionModel, error)) {
|
||||||
h.handler.HandleFunc(introspectionEndpoint, func(w http.ResponseWriter, r *http.Request) {
|
h.handler.HandleFunc(introspectionEndpoint, func(w http.ResponseWriter, r *http.Request) {
|
||||||
var introspectionReq x_oidc.IntrospectionReq
|
var introspectionReq x_oidc.IntrospectionReq
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
@@ -207,7 +207,7 @@ func (h *HttpHandler) Introspect(introspectionEndpoint string, handler func(ctx
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpHandler) RevokeToken(revocationEndpoint string, handler func(ctx context.Context, req *x_oidc.RevokeTokenReq, r *http.Request) error) {
|
func (h *HttpWrapper) RevokeToken(revocationEndpoint string, handler func(ctx context.Context, req *x_oidc.RevokeTokenReq, r *http.Request) error) {
|
||||||
h.handler.HandleFunc(revocationEndpoint, func(w http.ResponseWriter, r *http.Request) {
|
h.handler.HandleFunc(revocationEndpoint, func(w http.ResponseWriter, r *http.Request) {
|
||||||
var revokeTokenReq x_oidc.RevokeTokenReq
|
var revokeTokenReq x_oidc.RevokeTokenReq
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
@@ -246,7 +246,7 @@ func (h *HttpHandler) RevokeToken(revocationEndpoint string, handler func(ctx co
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpHandler) TokenExchange(tokenExchangeEndpoint string, handler func(ctx context.Context, req *x_oidc.TokenExchangeReq, r *http.Request) (interface{}, error)) {
|
func (h *HttpWrapper) TokenExchange(tokenExchangeEndpoint string, handler func(ctx context.Context, req *x_oidc.TokenExchangeReq, r *http.Request) (interface{}, error)) {
|
||||||
h.handler.HandleFunc(tokenExchangeEndpoint, func(w http.ResponseWriter, r *http.Request) {
|
h.handler.HandleFunc(tokenExchangeEndpoint, func(w http.ResponseWriter, r *http.Request) {
|
||||||
var tokenExchangeReq x_oidc.TokenExchangeReq
|
var tokenExchangeReq x_oidc.TokenExchangeReq
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
@@ -315,7 +315,7 @@ func (h *HttpHandler) TokenExchange(tokenExchangeEndpoint string, handler func(c
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpHandler) Userinfo(userinfoEndpoint string, handler func(ctx context.Context, req *x_oidc.UserinfoReq, r *http.Request) (*model.UserInfo, error)) {
|
func (h *HttpWrapper) Userinfo(userinfoEndpoint string, handler func(ctx context.Context, req *x_oidc.UserinfoReq, r *http.Request) (*model.UserInfo, error)) {
|
||||||
h.handler.HandleFunc(userinfoEndpoint, func(w http.ResponseWriter, r *http.Request) {
|
h.handler.HandleFunc(userinfoEndpoint, func(w http.ResponseWriter, r *http.Request) {
|
||||||
var userinfoReq x_oidc.UserinfoReq
|
var userinfoReq x_oidc.UserinfoReq
|
||||||
r.ParseForm()
|
r.ParseForm()
|
||||||
@@ -340,7 +340,7 @@ func (h *HttpHandler) Userinfo(userinfoEndpoint string, handler func(ctx context
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *HttpHandler) AuthorizeCallback(authorizeCallbackEndpoint string, handler func(ctx context.Context, req *x_oidc.AuthorizeCallbackReq) (callbackUrl string, err error)) {
|
func (h *HttpWrapper) AuthorizeCallback(authorizeCallbackEndpoint string, handler func(ctx context.Context, req *x_oidc.AuthorizeCallbackReq) (callbackUrl string, err error)) {
|
||||||
h.handler.HandleFunc(authorizeCallbackEndpoint, func(w http.ResponseWriter, r *http.Request) {
|
h.handler.HandleFunc(authorizeCallbackEndpoint, func(w http.ResponseWriter, r *http.Request) {
|
||||||
|
|
||||||
var authorizeCallbackReq x_oidc.AuthorizeCallbackReq
|
var authorizeCallbackReq x_oidc.AuthorizeCallbackReq
|
@@ -1,4 +1,4 @@
|
|||||||
package handler
|
package httpwrapper
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"embed"
|
"embed"
|
||||||
@@ -13,7 +13,7 @@ var (
|
|||||||
templates = template.Must(template.ParseFS(templateFS, "templates/*.html"))
|
templates = template.Must(template.ParseFS(templateFS, "templates/*.html"))
|
||||||
)
|
)
|
||||||
|
|
||||||
func (h *HttpHandler) login() {
|
func (h *HttpWrapper) login() {
|
||||||
h.handler.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
|
h.handler.HandleFunc("/login", func(w http.ResponseWriter, r *http.Request) {
|
||||||
err := r.ParseForm()
|
err := r.ParseForm()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -22,8 +22,7 @@ func (h *HttpHandler) login() {
|
|||||||
}
|
}
|
||||||
if r.Method == "GET" {
|
if r.Method == "GET" {
|
||||||
templates.ExecuteTemplate(w, "login", map[string]string{
|
templates.ExecuteTemplate(w, "login", map[string]string{
|
||||||
"ID": r.Form.Get("request_id"),
|
"ID": r.Form.Get("request_id"),
|
||||||
"Error": "",
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
})
|
})
|
23
example/server/httpwrapper/templates/login.html
Normal file
23
example/server/httpwrapper/templates/login.html
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
{{ define "login" -}}
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<title>Login</title>
|
||||||
|
</head>
|
||||||
|
<body style="display: flex; align-items: center; justify-content: center; height: 100vh;">
|
||||||
|
<form method="POST" action="/callback" style="height: 200px; width: 400px;">
|
||||||
|
<input type="hidden" name="id" value="{{.ID}}">
|
||||||
|
<div>
|
||||||
|
<label for="username">Username:</label>
|
||||||
|
<input id="username" name="username" style="width: 100%;height: 40px">
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="password">Password:(Correct password:test)</label>
|
||||||
|
<input id="password" type="password" name="password" style="width: 100%;height: 40px">
|
||||||
|
</div>
|
||||||
|
<button type="submit">Login</button>
|
||||||
|
</form>
|
||||||
|
</body>
|
||||||
|
</html>`
|
||||||
|
{{- end }}
|
@@ -3,23 +3,23 @@ package main
|
|||||||
import (
|
import (
|
||||||
"github.com/go-jose/go-jose/v3"
|
"github.com/go-jose/go-jose/v3"
|
||||||
x_oidc "github.com/xslasd/x-oidc"
|
x_oidc "github.com/xslasd/x-oidc"
|
||||||
"github.com/xslasd/x-oidc/crypto"
|
"github.com/xslasd/x-oidc/example/server/httpwrapper"
|
||||||
"github.com/xslasd/x-oidc/example/server/handler"
|
|
||||||
"github.com/xslasd/x-oidc/example/server/storage"
|
"github.com/xslasd/x-oidc/example/server/storage"
|
||||||
|
"github.com/xslasd/x-oidc/util"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
httpHandler := handler.NewHttpHandler(":8080")
|
httpHandler := httpwrapper.NewHttpHandler(":8080")
|
||||||
cr, err := crypto.NewJoseRSAJWT("private.pem", jose.RS256)
|
cr, err := util.NewJoseRSAJWT("private.pem", jose.RS256)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
_, err = x_oidc.NewOpenIDProvider(
|
_, err = x_oidc.NewOpenIDProvider(
|
||||||
&x_oidc.Config{
|
&x_oidc.Config{
|
||||||
Issuer: "http://localhost:8080",
|
Issuer: "http://localhost:8080",
|
||||||
Handler: httpHandler,
|
OpenIDWrapper: httpHandler,
|
||||||
Storage: storage.NewStorage(),
|
Storage: storage.NewStorage(),
|
||||||
Crypto: cr,
|
Crypto: cr,
|
||||||
},
|
},
|
||||||
x_oidc.WithAllowInsecure(true),
|
x_oidc.WithAllowInsecure(true),
|
||||||
)
|
)
|
||||||
|
@@ -79,7 +79,7 @@ func (t *TokenClaims) CheckAuthorizationContextClassReference(acr string) error
|
|||||||
type JWTClientTokenClaims struct {
|
type JWTClientTokenClaims struct {
|
||||||
Issuer string `json:"iss"`
|
Issuer string `json:"iss"`
|
||||||
Subject string `json:"sub"`
|
Subject string `json:"sub"`
|
||||||
Audience []string `json:"aud"` //todo array or string
|
Audience Audience `json:"aud"`
|
||||||
IssuedAt int64 `json:"iat"`
|
IssuedAt int64 `json:"iat"`
|
||||||
ExpiresAt int64 `json:"exp"`
|
ExpiresAt int64 `json:"exp"`
|
||||||
|
|
||||||
|
8
op.go
8
op.go
@@ -17,7 +17,7 @@ type OpenIDProvider struct {
|
|||||||
opt *OpenIDOption
|
opt *OpenIDOption
|
||||||
}
|
}
|
||||||
|
|
||||||
type OpenIDHandler interface {
|
type OpenIDWrapper interface {
|
||||||
SetLogger(logger log.Logger)
|
SetLogger(logger log.Logger)
|
||||||
|
|
||||||
DiscoveryJWKs(jwksEndpoint string, handler func() (*jose.JSONWebKeySet, error))
|
DiscoveryJWKs(jwksEndpoint string, handler func() (*jose.JSONWebKeySet, error))
|
||||||
@@ -38,7 +38,7 @@ func NewOpenIDProvider(cfg *Config, opts ...Option) (*OpenIDProvider, error) {
|
|||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
if cfg.Handler == nil {
|
if cfg.OpenIDWrapper == nil {
|
||||||
return nil, ecode.HandlerIsNull
|
return nil, ecode.HandlerIsNull
|
||||||
}
|
}
|
||||||
if cfg.Storage == nil {
|
if cfg.Storage == nil {
|
||||||
@@ -52,10 +52,10 @@ func NewOpenIDProvider(cfg *Config, opts ...Option) (*OpenIDProvider, error) {
|
|||||||
if !opt.allowInsecure && !util.IsHttpsPrefix(cfg.Issuer) {
|
if !opt.allowInsecure && !util.IsHttpsPrefix(cfg.Issuer) {
|
||||||
return nil, ecode.IssuerHTTPSInvalid
|
return nil, ecode.IssuerHTTPSInvalid
|
||||||
}
|
}
|
||||||
handler := srv.cfg.Handler
|
handler := srv.cfg.OpenIDWrapper
|
||||||
srv.printBanner()
|
srv.printBanner()
|
||||||
cfg.Storage.SetLogger(opt.logger)
|
cfg.Storage.SetLogger(opt.logger)
|
||||||
cfg.Handler.SetLogger(opt.logger)
|
cfg.OpenIDWrapper.SetLogger(opt.logger)
|
||||||
handler.DiscoveryJWKs(opt.jwksPath, srv.discoveryJWKs)
|
handler.DiscoveryJWKs(opt.jwksPath, srv.discoveryJWKs)
|
||||||
opt.logger.Infof("JWKsEndpoint -> %s", opt.jwksEndpoint)
|
opt.logger.Infof("JWKsEndpoint -> %s", opt.jwksEndpoint)
|
||||||
handler.DiscoveryConfig(opt.discoveryPath, srv.discoveryConfig)
|
handler.DiscoveryConfig(opt.discoveryPath, srv.discoveryConfig)
|
||||||
|
@@ -8,7 +8,6 @@ import (
|
|||||||
"github.com/go-jose/go-jose/v3"
|
"github.com/go-jose/go-jose/v3"
|
||||||
"github.com/go-jose/go-jose/v3/jwt"
|
"github.com/go-jose/go-jose/v3/jwt"
|
||||||
"github.com/xslasd/x-oidc/constant"
|
"github.com/xslasd/x-oidc/constant"
|
||||||
"github.com/xslasd/x-oidc/crypto"
|
|
||||||
"github.com/xslasd/x-oidc/ecode"
|
"github.com/xslasd/x-oidc/ecode"
|
||||||
"github.com/xslasd/x-oidc/model"
|
"github.com/xslasd/x-oidc/model"
|
||||||
"github.com/xslasd/x-oidc/util"
|
"github.com/xslasd/x-oidc/util"
|
||||||
@@ -66,7 +65,7 @@ func (o OIDCClient) GenerateCodeChallenge(CodeChallengeMethod string) string {
|
|||||||
return util.RandomString(43)
|
return util.RandomString(43)
|
||||||
case constant.CodeChallengeMethodS256:
|
case constant.CodeChallengeMethodS256:
|
||||||
codeChallenge := util.RandomString(43)
|
codeChallenge := util.RandomString(43)
|
||||||
return crypto.HashString(sha256.New(), codeChallenge, false)
|
return util.HashString(sha256.New(), codeChallenge, false)
|
||||||
}
|
}
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
|
@@ -6,9 +6,9 @@ import (
|
|||||||
"fmt"
|
"fmt"
|
||||||
"github.com/go-jose/go-jose/v3"
|
"github.com/go-jose/go-jose/v3"
|
||||||
"github.com/xslasd/x-oidc/constant"
|
"github.com/xslasd/x-oidc/constant"
|
||||||
"github.com/xslasd/x-oidc/crypto"
|
|
||||||
"github.com/xslasd/x-oidc/ecode"
|
"github.com/xslasd/x-oidc/ecode"
|
||||||
"github.com/xslasd/x-oidc/storage"
|
"github.com/xslasd/x-oidc/storage"
|
||||||
|
"github.com/xslasd/x-oidc/util"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"strings"
|
"strings"
|
||||||
@@ -136,8 +136,7 @@ func authorizeCodeChallenge(req *TokenExchangeReq, authReq *storage.AuthRequest)
|
|||||||
}
|
}
|
||||||
switch authReq.CodeChallengeMethod {
|
switch authReq.CodeChallengeMethod {
|
||||||
case constant.CodeChallengeMethodS256:
|
case constant.CodeChallengeMethodS256:
|
||||||
req.CodeVerifier = crypto.HashString(sha256.New(), req.CodeVerifier, false)
|
req.CodeVerifier = util.HashString(sha256.New(), req.CodeVerifier, false)
|
||||||
default:
|
|
||||||
}
|
}
|
||||||
if req.CodeVerifier != authReq.CodeChallenge {
|
if req.CodeVerifier != authReq.CodeChallenge {
|
||||||
fmt.Println("debug: CodeChallengeInvalid")
|
fmt.Println("debug: CodeChallengeInvalid")
|
||||||
|
@@ -24,17 +24,3 @@ func ValidateIssuer(issuer string) error {
|
|||||||
func IsHttpsPrefix(issuer string) bool {
|
func IsHttpsPrefix(issuer string) bool {
|
||||||
return strings.HasPrefix(issuer, constant.HttpsPrefix)
|
return strings.HasPrefix(issuer, constant.HttpsPrefix)
|
||||||
}
|
}
|
||||||
|
|
||||||
func GetQueryString(queryMap map[string]string) string {
|
|
||||||
if queryMap == nil || len(queryMap) == 0 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
queryValue := url.Values{}
|
|
||||||
for key, value := range queryMap {
|
|
||||||
if value == "" {
|
|
||||||
continue
|
|
||||||
}
|
|
||||||
queryValue.Add(key, value)
|
|
||||||
}
|
|
||||||
return queryValue.Encode()
|
|
||||||
}
|
|
||||||
|
@@ -1,9 +1,12 @@
|
|||||||
package crypto
|
package util
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"crypto/rand"
|
"crypto/rand"
|
||||||
"crypto/rsa"
|
"crypto/rsa"
|
||||||
|
"crypto/sha256"
|
||||||
|
"crypto/sha512"
|
||||||
"crypto/x509"
|
"crypto/x509"
|
||||||
|
"encoding/base64"
|
||||||
"encoding/hex"
|
"encoding/hex"
|
||||||
"encoding/pem"
|
"encoding/pem"
|
||||||
"fmt"
|
"fmt"
|
||||||
@@ -11,6 +14,7 @@ import (
|
|||||||
"github.com/go-jose/go-jose/v3/jwt"
|
"github.com/go-jose/go-jose/v3/jwt"
|
||||||
"github.com/google/uuid"
|
"github.com/google/uuid"
|
||||||
"github.com/xslasd/x-oidc/ecode"
|
"github.com/xslasd/x-oidc/ecode"
|
||||||
|
"hash"
|
||||||
"os"
|
"os"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -132,7 +136,6 @@ func (j JoseRSAJWT) ParseJWT(token string, payload interface{}) error {
|
|||||||
//}
|
//}
|
||||||
//
|
//
|
||||||
//func (j JoseHMACJWT) GenerateJWT(claims interface{}) (string, error) {
|
//func (j JoseHMACJWT) GenerateJWT(claims interface{}) (string, error) {
|
||||||
// // 创建一个 JWT 签名者
|
|
||||||
// signer, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: j.signingKey}, nil)
|
// signer, err := jose.NewSigner(jose.SigningKey{Algorithm: jose.HS256, Key: j.signingKey}, nil)
|
||||||
// if err != nil {
|
// if err != nil {
|
||||||
// fmt.Println("Error creating signer:", err)
|
// fmt.Println("Error creating signer:", err)
|
||||||
@@ -161,19 +164,26 @@ func (j JoseRSAJWT) ParseJWT(token string, payload interface{}) error {
|
|||||||
// err = json.Unmarshal(b, payload)
|
// err = json.Unmarshal(b, payload)
|
||||||
// return err
|
// return err
|
||||||
//}
|
//}
|
||||||
//
|
|
||||||
//func Sign(object interface{}, signingKey jose.SigningKey) (string, error) {
|
func GetHashAlgorithm(sigAlgorithm jose.SignatureAlgorithm) (hash.Hash, error) {
|
||||||
// signer, err := jose.NewSigner(signingKey, &jose.SignerOptions{})
|
switch sigAlgorithm {
|
||||||
// if err != nil {
|
case jose.RS256, jose.ES256, jose.PS256, jose.HS256:
|
||||||
// return "", err
|
return sha256.New(), nil
|
||||||
// }
|
case jose.RS384, jose.ES384, jose.PS384, jose.HS384:
|
||||||
// payload, err := json.Marshal(object)
|
return sha512.New384(), nil
|
||||||
// if err != nil {
|
case jose.RS512, jose.ES512, jose.PS512, jose.HS512:
|
||||||
// return "", err
|
return sha512.New(), nil
|
||||||
// }
|
default:
|
||||||
// result, err := signer.Sign(payload)
|
return nil, ecode.AlgorithmUnsupported.SetDescriptionf(string(sigAlgorithm))
|
||||||
// if err != nil {
|
}
|
||||||
// return "", err
|
}
|
||||||
// }
|
|
||||||
// return result.CompactSerialize()
|
func HashString(hash hash.Hash, s string, firstHalf bool) string {
|
||||||
//}
|
hash.Write([]byte(s))
|
||||||
|
size := hash.Size()
|
||||||
|
if firstHalf {
|
||||||
|
size = size / 2
|
||||||
|
}
|
||||||
|
sum := hash.Sum(nil)[:size]
|
||||||
|
return base64.RawURLEncoding.EncodeToString(sum)
|
||||||
|
}
|
Reference in New Issue
Block a user