Present nonce in id token

This commit is contained in:
LittleSheep 2024-07-28 22:30:51 +08:00
parent 6ef46d984d
commit 7c09138ef7
9 changed files with 51 additions and 32 deletions

View File

@ -3,9 +3,17 @@
<database-model serializer="dbm" dbms="POSTGRES" family-id="POSTGRES" format-version="4.52"> <database-model serializer="dbm" dbms="POSTGRES" family-id="POSTGRES" format-version="4.52">
<root id="1"> <root id="1">
<DateStyle>mdy</DateStyle> <DateStyle>mdy</DateStyle>
<IntrospectionStateNumber>10192</IntrospectionStateNumber> <Grants>1||-9223372036854775808|c|G
1||10|c|G
1||10|C|G
1||10|T|G
4||-9223372036854775808|c|G
4||10|c|G
4||10|C|G
4||10|T|G</Grants>
<IntrospectionStateNumber>10209</IntrospectionStateNumber>
<ServerVersion>16.3</ServerVersion> <ServerVersion>16.3</ServerVersion>
<StartupTime>1721488981</StartupTime> <StartupTime>1722154972</StartupTime>
<TimeZones>true ACDT <TimeZones>true ACDT
true ACSST true ACSST
false ACST false ACST
@ -800,7 +808,7 @@ false Zulu
13474||10|C|G 13474||10|C|G
13474||-9223372036854775808|U|G 13474||-9223372036854775808|U|G
13474||10|U|G</Grants> 13474||10|U|G</Grants>
<IntrospectionStateNumber>10192</IntrospectionStateNumber> <IntrospectionStateNumber>10209</IntrospectionStateNumber>
<ObjectId>37312</ObjectId> <ObjectId>37312</ObjectId>
<OwnerName>postgres</OwnerName> <OwnerName>postgres</OwnerName>
</database> </database>
@ -4241,8 +4249,8 @@ false Zulu
<schema id="268" parent="2" name="public"> <schema id="268" parent="2" name="public">
<Comment>standard public schema</Comment> <Comment>standard public schema</Comment>
<Current>1</Current> <Current>1</Current>
<IntrospectionStateNumber>10192</IntrospectionStateNumber> <IntrospectionStateNumber>10209</IntrospectionStateNumber>
<LastIntrospectionLocalTimestamp>2024-07-24.08:06:15</LastIntrospectionLocalTimestamp> <LastIntrospectionLocalTimestamp>2024-07-28.12:55:20</LastIntrospectionLocalTimestamp>
<ObjectId>2200</ObjectId> <ObjectId>2200</ObjectId>
<StateNumber>523</StateNumber> <StateNumber>523</StateNumber>
<OwnerName>pg_database_owner</OwnerName> <OwnerName>pg_database_owner</OwnerName>

View File

@ -1,2 +1,2 @@
#n:public #n:public
!<md> [10192, 0, null, null, -2147483648, -2147483648] !<md> [10209, 0, null, null, -2147483648, -2147483648]

5
.idea/workspace.xml generated
View File

@ -4,7 +4,10 @@
<option name="autoReloadType" value="ALL" /> <option name="autoReloadType" value="ALL" />
</component> </component>
<component name="ChangeListManager"> <component name="ChangeListManager">
<list default="true" id="3fefb2c4-b6f9-466b-a523-53352e8d6f95" name="更改" comment=":bug: Fix permissions in groups" /> <list default="true" id="3fefb2c4-b6f9-466b-a523-53352e8d6f95" name="更改" comment=":bug: Fix permissions in groups">
<change beforePath="$PROJECT_DIR$/.idea/dataSources/74bcf3ef-a2b9-435b-b9e5-f32902a33b25.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/dataSources/74bcf3ef-a2b9-435b-b9e5-f32902a33b25.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/.idea/dataSources/74bcf3ef-a2b9-435b-b9e5-f32902a33b25/storage_v2/_src_/database/hy_passport.gNOKQQ/schema/public.abK9xQ.meta" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/dataSources/74bcf3ef-a2b9-435b-b9e5-f32902a33b25/storage_v2/_src_/database/hy_passport.gNOKQQ/schema/public.abK9xQ.meta" afterDir="false" />
</list>
<option name="SHOW_DIALOG" value="false" /> <option name="SHOW_DIALOG" value="false" />
<option name="HIGHLIGHT_CONFLICTS" value="true" /> <option name="HIGHLIGHT_CONFLICTS" value="true" />
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />

View File

@ -39,6 +39,7 @@ type AuthTicket struct {
ExpiredAt *time.Time `json:"expired_at"` ExpiredAt *time.Time `json:"expired_at"`
AvailableAt *time.Time `json:"available_at"` AvailableAt *time.Time `json:"available_at"`
LastGrantAt *time.Time `json:"last_grant_at"` LastGrantAt *time.Time `json:"last_grant_at"`
Nonce *string `json:"nonce"`
ClientID *uint `json:"client_id"` ClientID *uint `json:"client_id"`
AccountID uint `json:"account_id"` AccountID uint `json:"account_id"`
} }

View File

@ -1,10 +1,11 @@
package api package api
import ( import (
"git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts"
"strings" "strings"
"time" "time"
"git.solsynth.dev/hydrogen/passport/pkg/internal/server/exts"
"git.solsynth.dev/hydrogen/passport/pkg/internal/database" "git.solsynth.dev/hydrogen/passport/pkg/internal/database"
"git.solsynth.dev/hydrogen/passport/pkg/internal/models" "git.solsynth.dev/hydrogen/passport/pkg/internal/models"
"git.solsynth.dev/hydrogen/passport/pkg/internal/services" "git.solsynth.dev/hydrogen/passport/pkg/internal/services"
@ -62,6 +63,7 @@ func authorizeThirdClient(c *fiber.Ctx) error {
id := c.Query("client_id") id := c.Query("client_id")
response := c.Query("response_type") response := c.Query("response_type")
redirect := c.Query("redirect_uri") redirect := c.Query("redirect_uri")
nonce := c.Query("nonce")
scope := c.Query("scope") scope := c.Query("scope")
if len(scope) <= 0 { if len(scope) <= 0 {
return fiber.NewError(fiber.StatusBadRequest, "invalid request params") return fiber.NewError(fiber.StatusBadRequest, "invalid request params")
@ -87,6 +89,7 @@ func authorizeThirdClient(c *fiber.Ctx) error {
[]string{"passport", client.Alias}, []string{"passport", client.Alias},
c.IP(), c.IP(),
c.Get(fiber.HeaderUserAgent), c.Get(fiber.HeaderUserAgent),
&nonce,
) )
if err != nil { if err != nil {
@ -107,6 +110,7 @@ func authorizeThirdClient(c *fiber.Ctx) error {
[]string{"passport", client.Alias}, []string{"passport", client.Alias},
c.IP(), c.IP(),
c.Get(fiber.HeaderUserAgent), c.Get(fiber.HeaderUserAgent),
&nonce,
) )
if err != nil { if err != nil {

View File

@ -22,6 +22,7 @@ type PayloadClaims struct {
// Additonal Stuff // Additonal Stuff
AuthorizedParties string `json:"azp,omitempty"` AuthorizedParties string `json:"azp,omitempty"`
Nonce string `json:"nonce,omitempty"`
Type string `json:"typ"` Type string `json:"typ"`
} }
@ -30,7 +31,7 @@ const (
JwtRefreshType = "refresh" JwtRefreshType = "refresh"
) )
func EncodeJwt(id string, typ, sub, sed string, aud []string, exp time.Time, idTokenUser ...models.Account) (string, error) { func EncodeJwt(id string, typ, sub, sed string, nonce *string, aud []string, exp time.Time, idTokenUser ...models.Account) (string, error) {
var azp string var azp string
for _, item := range aud { for _, item := range aud {
if item != InternalTokenAudience { if item != InternalTokenAudience {
@ -61,6 +62,10 @@ func EncodeJwt(id string, typ, sub, sed string, aud []string, exp time.Time, idT
claims.Email = user.GetPrimaryEmail().Content claims.Email = user.GetPrimaryEmail().Content
} }
if nonce != nil {
claims.Nonce = *nonce
}
tk := jwt.NewWithClaims(jwt.SigningMethodHS512, claims) tk := jwt.NewWithClaims(jwt.SigningMethodHS512, claims)
return tk.SignedString([]byte(viper.GetString("secret"))) return tk.SignedString([]byte(viper.GetString("secret")))

View File

@ -62,8 +62,12 @@ func NewOauthTicket(
user models.Account, user models.Account,
client models.ThirdClient, client models.ThirdClient,
claims, audiences []string, claims, audiences []string,
ip, ua string, ip, ua string, nonce *string,
) (models.AuthTicket, error) { ) (models.AuthTicket, error) {
if nonce != nil && len(*nonce) == 0 {
nonce = nil
}
ticket := models.AuthTicket{ ticket := models.AuthTicket{
Claims: claims, Claims: claims,
Audiences: audiences, Audiences: audiences,
@ -74,6 +78,7 @@ func NewOauthTicket(
RefreshToken: lo.ToPtr(uuid.NewString()), RefreshToken: lo.ToPtr(uuid.NewString()),
AvailableAt: lo.ToPtr(time.Now()), AvailableAt: lo.ToPtr(time.Now()),
ExpiredAt: lo.ToPtr(time.Now().Add(7 * 24 * time.Hour)), ExpiredAt: lo.ToPtr(time.Now().Add(7 * 24 * time.Hour)),
Nonce: nonce,
ClientID: &client.ID, ClientID: &client.ID,
AccountID: user.ID, AccountID: user.ID,
} }

View File

@ -25,11 +25,11 @@ func GetToken(ticket models.AuthTicket) (atk, rtk string, err error) {
sub := strconv.Itoa(int(ticket.AccountID)) sub := strconv.Itoa(int(ticket.AccountID))
sed := strconv.Itoa(int(ticket.ID)) sed := strconv.Itoa(int(ticket.ID))
atk, err = EncodeJwt(*ticket.AccessToken, JwtAccessType, sub, sed, ticket.Audiences, time.Now().Add(atkDeadline)) atk, err = EncodeJwt(*ticket.AccessToken, JwtAccessType, sub, sed, nil, ticket.Audiences, time.Now().Add(atkDeadline))
if err != nil { if err != nil {
return return
} }
rtk, err = EncodeJwt(*ticket.RefreshToken, JwtRefreshType, sub, sed, ticket.Audiences, time.Now().Add(rtkDeadline)) rtk, err = EncodeJwt(*ticket.RefreshToken, JwtRefreshType, sub, sed, nil, ticket.Audiences, time.Now().Add(rtkDeadline))
if err != nil { if err != nil {
return return
} }
@ -89,7 +89,7 @@ func ExchangeOauthToken(clientId, clientSecret, redirectUri, token string) (idk,
sub := strconv.Itoa(int(ticket.AccountID)) sub := strconv.Itoa(int(ticket.AccountID))
sed := strconv.Itoa(int(ticket.ID)) sed := strconv.Itoa(int(ticket.ID))
idk, err = EncodeJwt(*ticket.AccessToken, JwtAccessType, sub, sed, ticket.Audiences, time.Now().Add(24*time.Minute), user) idk, err = EncodeJwt(*ticket.AccessToken, JwtAccessType, sub, sed, ticket.Nonce, ticket.Audiences, time.Now().Add(24*time.Minute), user)
return return
} }

View File

@ -107,7 +107,7 @@ const requestedClaims = computed(() => {
const panel = ref("confirm") const panel = ref("confirm")
async function tryAuthorize() { async function tryAuthorize() {
const res = await request(`/api/auth/o/authorize${location.search}`, { const res = await request("/api/auth/o/authorize" + window.location.search, {
headers: { Authorization: `Bearer ${getAtk()}` }, headers: { Authorization: `Bearer ${getAtk()}` },
}) })
@ -139,19 +139,10 @@ function decline() {
async function approve() { async function approve() {
loading.value = true loading.value = true
const res = await request( const res = await request("/api/auth/o/authorize" + window.location.search, {
"/api/auth/o/authorize?" + method: "POST",
new URLSearchParams({ headers: { Authorization: `Bearer ${getAtk()}` },
client_id: route.query["client_id"] as string, })
redirect_uri: encodeURIComponent(route.query["redirect_uri"] as string),
response_type: "code",
scope: route.query["scope"] as string,
}),
{
method: "POST",
headers: { Authorization: `Bearer ${getAtk()}` },
},
)
if (res.status !== 200) { if (res.status !== 200) {
error.value = await res.text() error.value = await res.text()
@ -169,11 +160,13 @@ function callback(ticket: any) {
} }
function getClaimDescription(key: string): ClaimType { function getClaimDescription(key: string): ClaimType {
return Object.prototype.hasOwnProperty.call(claims, key) ? claims[key] : { return Object.prototype.hasOwnProperty.call(claims, key)
icon: "mdi-asterisk", ? claims[key]
name: key, : {
description: "Unknown claim...", icon: "mdi-asterisk",
} name: key,
description: "Unknown claim...",
}
} }
</script> </script>