chore(deps): bump github.com/libregraph/lico from 0.64.0 to 0.65.0

Bumps [github.com/libregraph/lico](https://github.com/libregraph/lico) from 0.64.0 to 0.65.0.
- [Changelog](https://github.com/libregraph/lico/blob/master/CHANGELOG.md)
- [Commits](https://github.com/libregraph/lico/compare/v0.64.0...v0.65.0)

---
updated-dependencies:
- dependency-name: github.com/libregraph/lico
  dependency-type: direct:production
  update-type: version-update:semver-minor
...

Signed-off-by: dependabot[bot] <support@github.com>
This commit is contained in:
dependabot[bot]
2024-12-04 06:19:31 +00:00
committed by Ralf Haferkamp
parent 58410b0b10
commit e08899d224
10 changed files with 99 additions and 26 deletions
+15 -1
View File
@@ -4,7 +4,21 @@
## v0.64.0 (2024-09-18)
## v0.65.0 (2024-11-26)
- Add login hint support
- Add legacy support via plugin
- Allow client redirect URI with only a scheme
- Bump braces from 3.0.2 to 3.0.3 in /identifier
- Bump path-to-regexp from 1.8.0 to 1.9.0 in /identifier
- Bump ws from 8.14.2 to 8.17.1 in /identifier
- Bump rollup from 2.79.1 to 2.79.2 in /identifier
- Bump github.com/golang-jwt/jwt/v4 from 4.5.0 to 4.5.1
- Keep extra backend provided id and access token claims on refresh
- Return id token when grant type is refresh token
## v0.64.0 (2024-09-19)
- Implement refresh and revoke for lg identifier backend session
- Pass real src ip and user agent to lg identifier backend
+2 -2
View File
@@ -35,10 +35,10 @@ func (i *Identifier) writeWebappIndexHTML(rw http.ResponseWriter, req *http.Requ
// FIXME(longsleep): Set a secure CSP. Right now we need `data:` for images
// since it is used. Since `data:` URLs possibly could allow xss, a better
// way should be found for our early loading inline SVG stuff.
rw.Header().Set("Content-Security-Policy", fmt.Sprintf("default-src 'self'; img-src 'self' data:; font-src 'self' data:; script-src 'self'; style-src 'self' 'nonce-%s'; base-uri 'none'; frame-ancestors 'none';", nonce))
rw.Header().Set("Content-Security-Policy", fmt.Sprintf("default-src 'self'; img-src 'self' data:; font-src 'self' data:; script-src 'self' 'nonce-%s'; style-src 'self' 'nonce-%s'; base-uri 'none'; frame-ancestors 'none';", nonce, nonce))
// Write index with random nonce to response.
index := bytes.Replace(i.webappIndexHTML, []byte("__CSP_NONCE__"), []byte(nonce), 1)
index := bytes.ReplaceAll(i.webappIndexHTML, []byte("__CSP_NONCE__"), []byte(nonce))
rw.Write(index)
}
+4
View File
@@ -25,6 +25,7 @@
"redux-logger": "^3.0.6",
"redux-thunk": "^2.4.2",
"render-if": "^0.1.1",
"validator": "^13.12.0",
"web-vitals": "^1.1.2"
},
"scripts": {
@@ -47,9 +48,11 @@
"@types/react-dom": "^17.0.23",
"@types/react-redux": "^7.1.25",
"@types/redux-logger": "^3.0.12",
"@types/validator": "^13",
"@typescript-eslint/eslint-plugin": "^6.11.0",
"@typescript-eslint/parser": "^6.9.0",
"@typescript-eslint/typescript-estree": "^6.11.0",
"@vitejs/plugin-legacy": "^4.0.0",
"@vitejs/plugin-react": "^4.1.1",
"cldr": "^7.4.0",
"eslint": "^8.53.0",
@@ -60,6 +63,7 @@
"if-node-version": "^1.1.1",
"jsdom": "^22.1.0",
"source-map-explorer": "^2.5.3",
"terser": "^5.30.4",
"typescript": "^5.2.2",
"vite": "^4.5.2",
"vite-plugin-checker": "^0.6.2",
+38 -8
View File
@@ -1,6 +1,31 @@
import { defineConfig, splitVendorChunkPlugin } from 'vite';
import react from '@vitejs/plugin-react';
import checker from 'vite-plugin-checker';
import { defineConfig, splitVendorChunkPlugin } from "vite";
import react from "@vitejs/plugin-react";
import checker from "vite-plugin-checker";
import legacy from "@vitejs/plugin-legacy";
const addScriptCSPNoncePlaceholderPlugin = () => {
return {
name: "add-script-nonce-placeholderP-plugin",
apply: "build",
transformIndexHtml: {
order: "post",
handler(htmlData) {
return htmlData.replaceAll(
/<script nomodule>/gi,
`<script nomodule nonce="__CSP_NONCE__">`
).replaceAll(
/<script type="module">/gi,
`<script type="module" nonce="__CSP_NONCE__">`
).replaceAll(
/<script nomodule crossorigin id="vite-legacy-entry"/gi,
`<script nomodule crossorigin id="vite-legacy-entry" nonce="__CSP_NONCE__"`
);
},
},
};
};
export default defineConfig((env) => {
return {
@@ -23,13 +48,18 @@ export default defineConfig((env) => {
},
plugins: [
react(),
env.mode !== 'test' && checker({
typescript: true,
eslint: {
lintCommand: 'eslint --max-warnings=0 src',
},
legacy({
targets: ['edge 18'],
}),
env.mode !== "test" &&
checker({
typescript: true,
eslint: {
lintCommand: 'eslint --max-warnings=0 src',
},
}),
splitVendorChunkPlugin(),
addScriptCSPNoncePlaceholderPlugin(),
],
test: {
globals: true,
+1 -1
View File
@@ -332,7 +332,7 @@ func (ar *AuthenticationRequest) Validate(keyFunc jwt.Keyfunc) error {
}
// TODO(longsleep): implement client_id white list.
if ar.RedirectURI == nil || ar.RedirectURI.Host == "" || ar.RedirectURI.Scheme == "" {
if ar.RedirectURI == nil || !ar.RedirectURI.IsAbs() {
return ar.NewBadRequest(oidc.ErrorCodeOAuth2InvalidRequest, "invalid or missing redirect_uri")
}
+9 -5
View File
@@ -239,7 +239,7 @@ func (p *Provider) AuthorizeResponse(rw http.ResponseWriter, req *http.Request,
// Create access token when requested.
if _, ok := ar.ResponseTypes[oidc.ResponseTypeToken]; ok {
accessTokenString, err = p.makeAccessToken(ctx, ar.ClientID, auth, nil)
accessTokenString, err = p.makeAccessToken(ctx, ar.ClientID, auth, nil, nil)
if err != nil {
goto done
}
@@ -248,7 +248,7 @@ func (p *Provider) AuthorizeResponse(rw http.ResponseWriter, req *http.Request,
// Create ID token when requested and granted.
if authorizedScopes[oidc.ScopeOpenID] {
if _, ok := ar.ResponseTypes[oidc.ResponseTypeIDToken]; ok {
idTokenString, err = p.makeIDToken(ctx, ar, auth, session, accessTokenString, codeString, nil)
idTokenString, err = p.makeIDToken(ctx, ar, auth, session, accessTokenString, codeString, nil, nil)
if err != nil {
goto done
}
@@ -330,6 +330,7 @@ func (p *Provider) TokenHandler(rw http.ResponseWriter, req *http.Request) {
var accessTokenString string
var idTokenString string
var refreshTokenString string
var refreshTokenClaims *konnect.RefreshTokenClaims
var approvedScopes map[string]bool
var authorizedScopes map[string]bool
var clientDetails *clients.Details
@@ -498,22 +499,25 @@ func (p *Provider) TokenHandler(rw http.ResponseWriter, req *http.Request) {
ClientID: claims.Audience,
}
// Remember refresh token claims, for use in access and id token generators later on.
refreshTokenClaims = claims
default:
err = konnectoidc.NewOAuth2Error(oidc.ErrorCodeOAuth2UnsupportedGrantType, "grant_type value not implemented")
goto done
}
// Create access token.
accessTokenString, err = p.makeAccessToken(ctx, ar.ClientID, auth, signinMethod)
accessTokenString, err = p.makeAccessToken(ctx, ar.ClientID, auth, signinMethod, refreshTokenClaims)
if err != nil {
goto done
}
switch tr.GrantType {
case oidc.GrantTypeAuthorizationCode:
case oidc.GrantTypeAuthorizationCode, oidc.GrantTypeRefreshToken:
// Create ID token when not previously requested amd openid scope is authorized.
if !ar.ResponseTypes[oidc.ResponseTypeIDToken] && authorizedScopes[oidc.ScopeOpenID] {
idTokenString, err = p.makeIDToken(ctx, ar, auth, session, accessTokenString, "", signinMethod)
idTokenString, err = p.makeIDToken(ctx, ar, auth, session, accessTokenString, "", signinMethod, refreshTokenClaims)
if err != nil {
goto done
}
+26 -3
View File
@@ -35,10 +35,10 @@ import (
// MakeAccessToken implements the oidc.AccessTokenProvider interface.
func (p *Provider) MakeAccessToken(ctx context.Context, audience string, auth identity.AuthRecord) (string, error) {
return p.makeAccessToken(ctx, audience, auth, nil)
return p.makeAccessToken(ctx, audience, auth, nil, nil)
}
func (p *Provider) makeAccessToken(ctx context.Context, audience string, auth identity.AuthRecord, signingMethod jwt.SigningMethod) (string, error) {
func (p *Provider) makeAccessToken(ctx context.Context, audience string, auth identity.AuthRecord, signingMethod jwt.SigningMethod, refreshTokenClaims *konnect.RefreshTokenClaims) (string, error) {
sk, ok := p.getSigningKey(signingMethod)
if !ok {
return "", fmt.Errorf("no signing key")
@@ -67,6 +67,17 @@ func (p *Provider) makeAccessToken(ctx context.Context, audience string, auth id
accessTokenClaims.IdentityClaims = userWithClaims.Claims()
}
accessTokenClaims.IdentityProvider = auth.Manager().Name()
if accessTokenClaims.IdentityClaims != nil && refreshTokenClaims != nil && refreshTokenClaims.IdentityClaims != nil {
if refreshTokenClaims.IdentityProvider != accessTokenClaims.IdentityProvider {
return "", fmt.Errorf("refresh token claims provider mismatch")
}
for k, v := range refreshTokenClaims.IdentityClaims {
// Force to use refresh token identity claim values. This also locks all
// the extra claims for id and access tokens to the ones provided from
// the refresh token claims (which currently includes the session id).
accessTokenClaims.IdentityClaims[k] = v
}
}
}
// Support additional custom user specific claims.
@@ -113,7 +124,7 @@ func (p *Provider) makeAccessToken(ctx context.Context, audience string, auth id
return accessToken.SignedString(sk.PrivateKey)
}
func (p *Provider) makeIDToken(ctx context.Context, ar *payload.AuthenticationRequest, auth identity.AuthRecord, session *payload.Session, accessTokenString string, codeString string, signingMethod jwt.SigningMethod) (string, error) {
func (p *Provider) makeIDToken(ctx context.Context, ar *payload.AuthenticationRequest, auth identity.AuthRecord, session *payload.Session, accessTokenString string, codeString string, signingMethod jwt.SigningMethod, refreshTokenClaims *konnect.RefreshTokenClaims) (string, error) {
sk, ok := p.getSigningKey(signingMethod)
if !ok {
return "", fmt.Errorf("no signing key")
@@ -160,6 +171,18 @@ func (p *Provider) makeIDToken(ctx context.Context, ar *payload.AuthenticationRe
if userWithClaims, ok := user.(identity.UserWithClaims); ok {
accessTokenClaims.IdentityClaims = userWithClaims.Claims()
}
accessTokenClaims.IdentityProvider = auth.Manager().Name()
if accessTokenClaims.IdentityClaims != nil && refreshTokenClaims != nil && refreshTokenClaims.IdentityClaims != nil {
if refreshTokenClaims.IdentityProvider != accessTokenClaims.IdentityProvider {
return "", fmt.Errorf("refresh token claims provider mismatch")
}
for k, v := range refreshTokenClaims.IdentityClaims {
// Force to use refresh token identity claim values. This also locks all
// the extra claims for id and access tokens to the ones provided from
// the refresh token claims (which currently includes the session id).
accessTokenClaims.IdentityClaims[k] = v
}
}
if withIDTokenClaimsRequest {
// Apply additional information from ID token claims request.