Make cert work.

This commit is contained in:
Yang Luo 2021-12-31 09:36:48 +08:00
parent ba1646a0c3
commit 5e8897e41b
18 changed files with 262 additions and 38 deletions

View File

@ -28,7 +28,7 @@ func (c *RootController) GetOidcDiscovery() {
// @Tag OIDC API
// @router /api/certs [get]
func (c *RootController) GetOidcCert() {
jwks, err := object.GetJSONWebKeySet()
jwks, err := object.GetJsonWebKeySet()
if err != nil {
c.ResponseError(err.Error())
return

View File

@ -31,6 +31,7 @@ type Application struct {
HomepageUrl string `xorm:"varchar(100)" json:"homepageUrl"`
Description string `xorm:"varchar(100)" json:"description"`
Organization string `xorm:"varchar(100)" json:"organization"`
Cert string `xorm:"varchar(100)" json:"cert"`
EnablePassword bool `json:"enablePassword"`
EnableSignUp bool `json:"enableSignUp"`
EnableSigninSession bool `json:"enableSigninSession"`

View File

@ -124,6 +124,12 @@ func UpdateCert(id string, cert *Cert) bool {
}
func AddCert(cert *Cert) bool {
if cert.PublicKey == "" || cert.PrivateKey == "" {
publicKey, privateKey := generateRsaKeys(cert.BitSize, cert.ExpireInYears, cert.Name, cert.Owner)
cert.PublicKey = publicKey
cert.PrivateKey = privateKey
}
affected, err := adapter.Engine.Insert(cert)
if err != nil {
panic(err)
@ -144,3 +150,15 @@ func DeleteCert(cert *Cert) bool {
func (p *Cert) GetId() string {
return fmt.Sprintf("%s/%s", p.Owner, p.Name)
}
func getCertByApplication(application *Application) *Cert {
if application.Cert != "" {
return getCert("admin", application.Cert)
} else {
return GetDefaultCert()
}
}
func GetDefaultCert() *Cert {
return getCert("admin", "cert-built-in")
}

View File

@ -14,12 +14,23 @@
package object
import "github.com/casbin/casdoor/util"
import (
_ "embed"
"github.com/casbin/casdoor/util"
)
//go:embed token_jwt_key.pem
var tokenJwtPublicKey string
//go:embed token_jwt_key.key
var tokenJwtPrivateKey string
func InitDb() {
initBuiltInOrganization()
initBuiltInUser()
initBuiltInApplication()
initBuiltInCert()
initBuiltInLdap()
}
@ -90,6 +101,7 @@ func initBuiltInApplication() {
Logo: "https://cdn.casbin.com/logo/logo_1024x256.png",
HomepageUrl: "https://casdoor.org",
Organization: "built-in",
Cert: "cert-built-in",
EnablePassword: true,
EnableSignUp: true,
Providers: []*ProviderItem{},
@ -109,6 +121,28 @@ func initBuiltInApplication() {
AddApplication(application)
}
func initBuiltInCert() {
cert := getCert("admin", "cert-built-in")
if cert != nil {
return
}
cert = &Cert{
Owner: "admin",
Name: "cert-built-in",
CreatedTime: util.GetCurrentTime(),
DisplayName: "Built-in Cert",
Scope: "JWT",
Type: "x509",
CryptoAlgorithm: "RSA",
BitSize: 4096,
ExpireInYears: 20,
PublicKey: tokenJwtPublicKey,
PrivateKey: tokenJwtPrivateKey,
}
AddCert(cert)
}
func initBuiltInLdap() {
ldap := GetLdap("ldap-built-in")
if ldap != nil {

View File

@ -72,13 +72,15 @@ func GetOidcDiscovery() OidcDiscovery {
return oidcDiscovery
}
func GetJSONWebKeySet() (jose.JSONWebKeySet, error) {
func GetJsonWebKeySet() (jose.JSONWebKeySet, error) {
cert := GetDefaultCert()
//follows the protocol rfc 7517(draft)
//link here: https://self-issued.info/docs/draft-ietf-jose-json-web-key.html
//or https://datatracker.ietf.org/doc/html/draft-ietf-jose-json-web-key
certPEMBlock := []byte(tokenJwtPublicKey)
certDERBlock, _ := pem.Decode(certPEMBlock)
x509Cert, _ := x509.ParseCertificate(certDERBlock.Bytes)
certPemBlock := []byte(cert.PublicKey)
certDerBlock, _ := pem.Decode(certPemBlock)
x509Cert, _ := x509.ParseCertificate(certDerBlock.Bytes)
var jwk jose.JSONWebKey
jwk.Key = x509Cert.PublicKey

View File

@ -332,7 +332,9 @@ func RefreshToken(grantType string, refreshToken string, scope string, clientId
Code: "",
}
}
claims, err := ParseJwtToken(refreshToken)
cert := getCertByApplication(application)
claims, err := ParseJwtToken(refreshToken, cert)
if err != nil {
return &Code{
Message: "error: invalid refresh_token",

View File

@ -23,12 +23,6 @@ import (
"github.com/golang-jwt/jwt/v4"
)
//go:embed token_jwt_key.pem
var tokenJwtPublicKey string
//go:embed token_jwt_key.key
var tokenJwtPrivateKey string
type Claims struct {
*User
Name string `json:"name,omitempty"`
@ -68,9 +62,10 @@ func generateJwtToken(application *Application, user *User, nonce string) (strin
claims.ExpiresAt = jwt.NewNumericDate(refreshExpireTime)
refreshToken := jwt.NewWithClaims(jwt.SigningMethodRS256, claims)
// Use "token_jwt_key.key" as RSA private key
privateKey := tokenJwtPrivateKey
key, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(privateKey))
cert := getCertByApplication(application)
// RSA private key
key, err := jwt.ParseRSAPrivateKeyFromPEM([]byte(cert.PrivateKey))
if err != nil {
return "", "", err
}
@ -84,14 +79,14 @@ func generateJwtToken(application *Application, user *User, nonce string) (strin
return tokenString, refreshTokenString, err
}
func ParseJwtToken(token string) (*Claims, error) {
func ParseJwtToken(token string, cert *Cert) (*Claims, error) {
t, err := jwt.ParseWithClaims(token, &Claims{}, func(token *jwt.Token) (interface{}, error) {
if _, ok := token.Method.(*jwt.SigningMethodRSA); !ok {
return nil, fmt.Errorf("unexpected signing method: %v", token.Header["alg"])
}
// Use "token_jwt_key.pem" as RSA public key
publicKey, err := jwt.ParseRSAPublicKeyFromPEM([]byte(tokenJwtPublicKey))
// RSA public key
publicKey, err := jwt.ParseRSAPublicKeyFromPEM([]byte(cert.PublicKey))
if err != nil {
return nil, err
}

View File

@ -20,19 +20,14 @@ import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"fmt"
"math/big"
"time"
"github.com/casbin/casdoor/util"
)
func generateRsaKeys(fileId string) {
func generateRsaKeys(bitSize int, expireInYears int, commonName string, organization string) (string, string) {
// https://stackoverflow.com/questions/64104586/use-golang-to-get-rsa-key-the-same-way-openssl-genrsa
// https://stackoverflow.com/questions/43822945/golang-can-i-create-x509keypair-using-rsa-key
bitSize := 4096
// Generate RSA key.
key, err := rsa.GenerateKey(rand.Reader, bitSize)
if err != nil {
@ -50,12 +45,12 @@ func generateRsaKeys(fileId string) {
tml := x509.Certificate{
// you can add any attr that you need
NotBefore: time.Now(),
NotAfter: time.Now().AddDate(20, 0, 0),
NotAfter: time.Now().AddDate(expireInYears, 0, 0),
// you have to generate a different serial number each execution
SerialNumber: big.NewInt(123456),
Subject: pkix.Name{
CommonName: "Casdoor Cert",
Organization: []string{"Casdoor Organization"},
CommonName: commonName,
Organization: []string{organization},
},
BasicConstraintsValid: true,
}
@ -70,9 +65,5 @@ func generateRsaKeys(fileId string) {
Bytes: cert,
})
// Write private key to file.
util.WriteBytesToPath(privateKeyPem, fmt.Sprintf("%s.key", fileId))
// Write certificate (aka public key) to file.
util.WriteBytesToPath(certPem, fmt.Sprintf("%s.pem", fileId))
return string(certPem), string(privateKeyPem)
}

View File

@ -14,9 +14,20 @@
package object
import "testing"
import (
"fmt"
"testing"
"github.com/casbin/casdoor/util"
)
func TestGenerateRsaKeys(t *testing.T) {
fileId := "token_jwt_key"
generateRsaKeys(fileId)
publicKey, privateKey := generateRsaKeys(4096, 20, "Casdoor Cert", "Casdoor Organization")
// Write certificate (aka public key) to file.
util.WriteStringToPath(publicKey, fmt.Sprintf("%s.pem", fileId))
// Write private key to file.
util.WriteStringToPath(privateKey, fmt.Sprintf("%s.key", fileId))
}

View File

@ -31,7 +31,8 @@ func AutoSigninFilter(ctx *context.Context) {
// "/page?access_token=123"
accessToken := ctx.Input.Query("accessToken")
if accessToken != "" {
claims, err := object.ParseJwtToken(accessToken)
cert := object.GetDefaultCert()
claims, err := object.ParseJwtToken(accessToken, cert)
if err != nil {
responseError(ctx, "invalid JWT token")
return
@ -71,7 +72,8 @@ func AutoSigninFilter(ctx *context.Context) {
// Authorization: Bearer bearerToken
bearerToken := parseBearerToken(ctx)
if bearerToken != "" {
claims, err := object.ParseJwtToken(bearerToken)
cert := object.GetDefaultCert()
claims, err := object.ParseJwtToken(bearerToken, cert)
if err != nil {
responseError(ctx, err.Error())
return

View File

@ -137,7 +137,7 @@ class UserListPage extends BaseListPage {
title: i18next.t("general:Name"),
dataIndex: 'name',
key: 'name',
width: (Setting.isMobile()) ? "80px" : "100px",
width: (Setting.isMobile()) ? "80px" : "110px",
fixed: 'left',
sorter: true,
...this.getColumnSearchProps('name'),

View File

@ -33,6 +33,29 @@
"Token format": "Token format",
"Token format - Tooltip": "Token format - Tooltip"
},
"cert": {
"Bit size": "Bit size",
"Bit size - Tooltip": "Bit size - Tooltip",
"Copy private key": "Copy private key",
"Copy public key": "Copy public key",
"Crypto algorithm": "Crypto algorithm",
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
"Download private key": "Download private key",
"Download public key": "Download public key",
"Edit Cert": "Edit Cert",
"Expire in years": "Expire in years",
"Expire in years - Tooltip": "Expire in years - Tooltip",
"Private key": "Private key",
"Private key - Tooltip": "Private key - Tooltip",
"Private key copied to clipboard successfully": "Private key copied to clipboard successfully",
"Public key": "Public key",
"Public key - Tooltip": "Public key - Tooltip",
"Public key copied to clipboard successfully": "Public key copied to clipboard successfully",
"Scope": "Scope",
"Scope - Tooltip": "Scope - Tooltip",
"Type": "Type",
"Type - Tooltip": "Type - Tooltip"
},
"code": {
"Code You Received": "Code You Received",
"Email code": "Email code",
@ -69,6 +92,7 @@
"Avatar - Tooltip": "Avatar to show to others",
"Back Home": "Back Home",
"Captcha": "Captcha",
"Certs": "Certs",
"Client IP": "Client IP",
"Created time": "Created time",
"Default avatar": "Default avatar",

View File

@ -33,6 +33,29 @@
"Token format": "Token format",
"Token format - Tooltip": "Token format - Tooltip"
},
"cert": {
"Bit size": "Bit size",
"Bit size - Tooltip": "Bit size - Tooltip",
"Copy private key": "Copy private key",
"Copy public key": "Copy public key",
"Crypto algorithm": "Crypto algorithm",
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
"Download private key": "Download private key",
"Download public key": "Download public key",
"Edit Cert": "Edit Cert",
"Expire in years": "Expire in years",
"Expire in years - Tooltip": "Expire in years - Tooltip",
"Private key": "Private key",
"Private key - Tooltip": "Private key - Tooltip",
"Private key copied to clipboard successfully": "Private key copied to clipboard successfully",
"Public key": "Public key",
"Public key - Tooltip": "Public key - Tooltip",
"Public key copied to clipboard successfully": "Public key copied to clipboard successfully",
"Scope": "Scope",
"Scope - Tooltip": "Scope - Tooltip",
"Type": "Type",
"Type - Tooltip": "Type - Tooltip"
},
"code": {
"Code You Received": "Code You Received",
"Email code": "Email code",
@ -69,6 +92,7 @@
"Avatar - Tooltip": "Avatar - Tooltip",
"Back Home": "Back Home",
"Captcha": "Captcha",
"Certs": "Certs",
"Client IP": "Client IP",
"Created time": "Created time",
"Default avatar": "Default avatar",

View File

@ -33,6 +33,29 @@
"Token format": "Token format",
"Token format - Tooltip": "Token format - Tooltip"
},
"cert": {
"Bit size": "Bit size",
"Bit size - Tooltip": "Bit size - Tooltip",
"Copy private key": "Copy private key",
"Copy public key": "Copy public key",
"Crypto algorithm": "Crypto algorithm",
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
"Download private key": "Download private key",
"Download public key": "Download public key",
"Edit Cert": "Edit Cert",
"Expire in years": "Expire in years",
"Expire in years - Tooltip": "Expire in years - Tooltip",
"Private key": "Private key",
"Private key - Tooltip": "Private key - Tooltip",
"Private key copied to clipboard successfully": "Private key copied to clipboard successfully",
"Public key": "Public key",
"Public key - Tooltip": "Public key - Tooltip",
"Public key copied to clipboard successfully": "Public key copied to clipboard successfully",
"Scope": "Scope",
"Scope - Tooltip": "Scope - Tooltip",
"Type": "Type",
"Type - Tooltip": "Type - Tooltip"
},
"code": {
"Code You Received": "Code You Received",
"Email code": "Email code",
@ -69,6 +92,7 @@
"Avatar - Tooltip": "Avatar to show to others",
"Back Home": "Back Home",
"Captcha": "Captcha",
"Certs": "Certs",
"Client IP": "Client IP",
"Created time": "Created time",
"Default avatar": "Default avatar",

View File

@ -33,6 +33,29 @@
"Token format": "Token format",
"Token format - Tooltip": "Token format - Tooltip"
},
"cert": {
"Bit size": "Bit size",
"Bit size - Tooltip": "Bit size - Tooltip",
"Copy private key": "Copy private key",
"Copy public key": "Copy public key",
"Crypto algorithm": "Crypto algorithm",
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
"Download private key": "Download private key",
"Download public key": "Download public key",
"Edit Cert": "Edit Cert",
"Expire in years": "Expire in years",
"Expire in years - Tooltip": "Expire in years - Tooltip",
"Private key": "Private key",
"Private key - Tooltip": "Private key - Tooltip",
"Private key copied to clipboard successfully": "Private key copied to clipboard successfully",
"Public key": "Public key",
"Public key - Tooltip": "Public key - Tooltip",
"Public key copied to clipboard successfully": "Public key copied to clipboard successfully",
"Scope": "Scope",
"Scope - Tooltip": "Scope - Tooltip",
"Type": "Type",
"Type - Tooltip": "Type - Tooltip"
},
"code": {
"Code You Received": "Code You Received",
"Email code": "Email code",
@ -69,6 +92,7 @@
"Avatar - Tooltip": "Avatar to show to others",
"Back Home": "Back Home",
"Captcha": "Captcha",
"Certs": "Certs",
"Client IP": "Client IP",
"Created time": "Created time",
"Default avatar": "Default avatar",

View File

@ -33,6 +33,29 @@
"Token format": "Token format",
"Token format - Tooltip": "Token format - Tooltip"
},
"cert": {
"Bit size": "Bit size",
"Bit size - Tooltip": "Bit size - Tooltip",
"Copy private key": "Copy private key",
"Copy public key": "Copy public key",
"Crypto algorithm": "Crypto algorithm",
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
"Download private key": "Download private key",
"Download public key": "Download public key",
"Edit Cert": "Edit Cert",
"Expire in years": "Expire in years",
"Expire in years - Tooltip": "Expire in years - Tooltip",
"Private key": "Private key",
"Private key - Tooltip": "Private key - Tooltip",
"Private key copied to clipboard successfully": "Private key copied to clipboard successfully",
"Public key": "Public key",
"Public key - Tooltip": "Public key - Tooltip",
"Public key copied to clipboard successfully": "Public key copied to clipboard successfully",
"Scope": "Scope",
"Scope - Tooltip": "Scope - Tooltip",
"Type": "Type",
"Type - Tooltip": "Type - Tooltip"
},
"code": {
"Code You Received": "Code You Received",
"Email code": "Email code",
@ -69,6 +92,7 @@
"Avatar - Tooltip": "Avatar to show to others",
"Back Home": "Back Home",
"Captcha": "Captcha",
"Certs": "Certs",
"Client IP": "Client IP",
"Created time": "Created time",
"Default avatar": "Default avatar",

View File

@ -33,6 +33,29 @@
"Token format": "Token format",
"Token format - Tooltip": "Token format - Tooltip"
},
"cert": {
"Bit size": "Bit size",
"Bit size - Tooltip": "Bit size - Tooltip",
"Copy private key": "Copy private key",
"Copy public key": "Copy public key",
"Crypto algorithm": "Crypto algorithm",
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
"Download private key": "Download private key",
"Download public key": "Download public key",
"Edit Cert": "Edit Cert",
"Expire in years": "Expire in years",
"Expire in years - Tooltip": "Expire in years - Tooltip",
"Private key": "Private key",
"Private key - Tooltip": "Private key - Tooltip",
"Private key copied to clipboard successfully": "Private key copied to clipboard successfully",
"Public key": "Public key",
"Public key - Tooltip": "Public key - Tooltip",
"Public key copied to clipboard successfully": "Public key copied to clipboard successfully",
"Scope": "Scope",
"Scope - Tooltip": "Scope - Tooltip",
"Type": "Type",
"Type - Tooltip": "Type - Tooltip"
},
"code": {
"Code You Received": "Code You Received",
"Email code": "Email code",
@ -69,6 +92,7 @@
"Avatar - Tooltip": "Avatar to show to others",
"Back Home": "Back Home",
"Captcha": "Captcha",
"Certs": "Certs",
"Client IP": "Client IP",
"Created time": "Created time",
"Default avatar": "Default avatar",

View File

@ -33,6 +33,29 @@
"Token format": "Access Token格式",
"Token format - Tooltip": "Access Token格式"
},
"cert": {
"Bit size": "位大小",
"Bit size - Tooltip": "Bit size - Tooltip",
"Copy private key": "复制私钥",
"Copy public key": "复制公钥",
"Crypto algorithm": "加密算法",
"Crypto algorithm - Tooltip": "Crypto algorithm - Tooltip",
"Download private key": "下载私钥",
"Download public key": "下载公钥",
"Edit Cert": "修改证书",
"Expire in years": "有效期(年)",
"Expire in years - Tooltip": "Expire in years - Tooltip",
"Private key": "私钥",
"Private key - Tooltip": "Private key - Tooltip",
"Private key copied to clipboard successfully": "私钥已成功复制到剪贴板",
"Public key": "公钥",
"Public key - Tooltip": "Public key - Tooltip",
"Public key copied to clipboard successfully": "公钥已成功复制到剪贴板",
"Scope": "用途",
"Scope - Tooltip": "Scope - Tooltip",
"Type": "类型",
"Type - Tooltip": "Type - Tooltip"
},
"code": {
"Code You Received": "验证码",
"Email code": "邮箱验证码",
@ -69,6 +92,7 @@
"Avatar - Tooltip": "向其他人展示的头像",
"Back Home": "返回到首页",
"Captcha": "人机验证码",
"Certs": "证书",
"Client IP": "客户端IP",
"Created time": "创建时间",
"Default avatar": "默认头像",