Skip to content

Commit 8ec424b

Browse files
authored
Introspect (#103)
* Support Introspect Calls * Enhance Doc
1 parent 5586c16 commit 8ec424b

File tree

4 files changed

+73
-6
lines changed

4 files changed

+73
-6
lines changed

README.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,9 @@ Command: (authorization_code is default)
3939
token-exchange Perform OAuth2 Token Exchange (RFC 8693).
4040
jwt-bearer Perform OAuth2 JWT Bearer Grant Type.
4141
saml-bearer Perform OAuth2 SAML 2.0 Bearer Grant Type.
42-
passcode Retrieve user passcode from X509 user authentication.
42+
passcode Retrieve user passcode from X509 user authentication. Need user_tls for user authentication.
43+
idp_token Retrieve trusted IdP token. Need assertion for user trust and client authentication.
44+
introspect Perform OAuth2 Introspection Endpoint Call. Need token input parameter.
4345
version Show version.
4446
help Show this help for more details.
4547
@@ -64,7 +66,9 @@ Flags:
6466
-refresh Bool flag. Default false. If true, call refresh flow for the received id_token.
6567
-idp_token Bool flag. Default false. If true, call the OIDC IdP token exchange endpoint (IAS specific only) and return the response.
6668
-idp_scope OIDC scope parameter. Default no scope is set. If you set the parameter idp_scope, it is set in IdP token exchange endpoint (IAS specific only).
69+
-introspect Bool flag. Default false. If true, call the OIDC token introspect endpoint (if provided in well-known) and return the response.
6770
-refresh_expiry Value in seconds. Optional parameter to reduce Refresh Token Lifetime.
71+
-token Input token for token introspect and token-exchange calls.
6872
-token_format Format for access_token. Possible values are opaque and jwt. Optional parameter, default: opaque
6973
-app_tid Optional parameter for IAS multi-tenant applications.
7074
-cmd Single command to be executed. Supported commands currently: jwks, client_credentials, password

openid-client/openid-client.go

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ func main() {
4343
" saml-bearer Perform OAuth2 SAML 2.0 Bearer Grant Type.\n" +
4444
" passcode Retrieve user passcode from X509 user authentication. Need user_tls for user authentication.\n" +
4545
" idp_token Retrieve trusted IdP token. Need assertion for user trust and client authentication.\n" +
46+
" introspect Perform OAuth2 Introspection Endpoint Call. Need token input parameter.\n" +
4647
" version Show version.\n" +
4748
" help Show this help for more details.\n" +
4849
"\n" +
@@ -67,7 +68,9 @@ func main() {
6768
" -refresh Bool flag. Default false. If true, call refresh flow for the received id_token.\n" +
6869
" -idp_token Bool flag. Default false. If true, call the OIDC IdP token exchange endpoint (IAS specific only) and return the response.\n" +
6970
" -idp_scope OIDC scope parameter. Default no scope is set. If you set the parameter idp_scope, it is set in IdP token exchange endpoint (IAS specific only).\n" +
71+
" -introspect Bool flag. Default false. If true, call the OIDC token introspect endpoint (if provided in well-known) and return the response.\n" +
7072
" -refresh_expiry Value in seconds. Optional parameter to reduce Refresh Token Lifetime.\n" +
73+
" -token Input token for token introspect and token-exchange calls.\n" +
7174
" -token_format Format for access_token. Possible values are opaque and jwt. Optional parameter, default: opaque\n" +
7275
" -app_tid Optional parameter for IAS multi-tenant applications.\n" +
7376
" -cmd Single command to be executed. Supported commands currently: jwks, client_credentials, password\n" +
@@ -99,6 +102,7 @@ func main() {
99102
var promptParameter = flag.String("prompt", "", "OIDC nonce parameter")
100103
var maxAgeParameter = flag.String("max_age", "", "OIDC nonce parameter")
101104
var doCorpIdpTokenExchange = flag.Bool("idp_token", false, "Return OIDC IdP token response")
105+
var doIntrospect = flag.Bool("introspect", false, "Call introspect with received id_token")
102106
var refreshExpiry = flag.String("refresh_expiry", "", "Value in seconds to reduce Refresh Token Lifetime")
103107
var tokenFormatParameter = flag.String("token_format", "opaque", "Format for access_token")
104108
var portParameter = flag.String("port", "8080", "Callback port on localhost")
@@ -120,6 +124,7 @@ func main() {
120124
var appTid = flag.String("app_tid", "", "Application tenant ID")
121125
var command = flag.String("cmd", "", "Single command to be executed")
122126
var assertionToken = flag.String("assertion", "", "Input token for token exchanges")
127+
var tokenInput = flag.String("token", "", "Input token for token introspect or revoke")
123128
var subjectType = flag.String("subject_type", "", "Token input type")
124129
var requestedType = flag.String("requested_type", "", "Token-Exchange requested type")
125130
var providerName = flag.String("provider_name", "", "Provider name for token-exchange")
@@ -148,8 +153,10 @@ func main() {
148153
showVersion()
149154
return
150155
case "client_credentials", "password", "token-exchange", "jwt-bearer", "saml-bearer", "idp_token", "":
151-
case "passcode":
152-
*clientID = "T000000" /* default */
156+
case "passcode", "introspect":
157+
if *clientID == "" {
158+
*clientID = "T000000" /* default */
159+
}
153160
case "authorization_code":
154161
*command = "" /* default command */
155162
default:
@@ -180,6 +187,7 @@ func main() {
180187
AuthorizeEndpoint string `json:"authorization_endpoint"`
181188
EndSessionEndpoint string `json:"end_session_endpoint"`
182189
TokenEndPoint string `json:"token_endpoint"`
190+
IntroSpectEndpoint string `json:"introspection_endpoint,omitempty"`
183191
}
184192
provider, oidcError := oidc.NewProvider(ctx, *issEndPoint)
185193
if oidcError != nil {
@@ -199,6 +207,7 @@ func main() {
199207
tlsClient := &http.Client{
200208
Transport: &http.Transport{
201209
TLSClientConfig: &tls.Config{
210+
Renegotiation: tls.RenegotiateOnceAsClient,
202211
InsecureSkipVerify: *skipTlsVerification,
203212
},
204213
},
@@ -272,7 +281,8 @@ func main() {
272281
tlsClient = &http.Client{
273282
Transport: &http.Transport{
274283
TLSClientConfig: &tls.Config{
275-
Certificates: []tls.Certificate{cert},
284+
Renegotiation: tls.RenegotiateOnceAsClient,
285+
Certificates: []tls.Certificate{cert},
276286
},
277287
},
278288
}
@@ -385,9 +395,14 @@ func main() {
385395
} else if *command == "token-exchange" {
386396
requestMap.Set("grant_type", "urn:ietf:params:oauth:grant-type:token-exchange")
387397
if *assertionToken == "" {
388-
log.Fatal("assertion parameter not set. Needed to pass it to subject_token for token-exchange")
398+
if *tokenInput != "" {
399+
requestMap.Set("subject_token", *tokenInput)
400+
} else {
401+
log.Fatal("assertion and/or token parameter not set. Needed to pass it to subject_token for token-exchange")
402+
}
403+
} else {
404+
requestMap.Set("subject_token", *assertionToken)
389405
}
390-
requestMap.Set("subject_token", *assertionToken)
391406
if *subjectType == "" {
392407
log.Fatal("subject_type parameter not set. Supported parameters for token-exchange are, id_token, access_token, refresh_token, jwt")
393408
} else {
@@ -463,6 +478,16 @@ func main() {
463478
fmt.Println("Response from endpoint /exchange/corporateidp")
464479
}
465480
fmt.Println(string(data))
481+
} else if *command == "introspect" {
482+
if *tokenInput == "" {
483+
log.Fatal("token parameter not set. Needed to pass it for validation")
484+
}
485+
if *clientID != "" && *clientID != "T000000" {
486+
requestMap.Set("client_id", *clientID)
487+
} else {
488+
requestMap.Del("client_id")
489+
}
490+
client.HandleTokenIntrospect(requestMap, *tokenInput, claims.IntroSpectEndpoint, *tlsClient, verbose)
466491
} else if *command == "jwks" {
467492
}
468493
} else {
@@ -523,6 +548,11 @@ func main() {
523548
var exchangedTokenResponse = client.HandleTokenExchangeGrant(requestMap, claims.TokenEndPoint, *tlsClient, verbose)
524549
fmt.Println(exchangedTokenResponse)
525550
}
551+
if *doIntrospect && idToken != "" && claims.IntroSpectEndpoint != "" {
552+
requestMap := url.Values{}
553+
requestMap.Set("client_id", *clientID)
554+
client.HandleTokenIntrospect(requestMap, idToken, claims.IntroSpectEndpoint, *tlsClient, verbose)
555+
}
526556
}
527557
}
528558

pkg/client/client.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,7 @@ func HandleRefreshFlow(clientID string, appTid string, clientSecret string, exis
286286
client := &http.Client{
287287
Transport: &http.Transport{
288288
TLSClientConfig: &tls.Config{
289+
Renegotiation: tls.RenegotiateOnceAsClient,
289290
InsecureSkipVerify: skipTlsVerification,
290291
},
291292
},

pkg/client/exchange.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -213,3 +213,35 @@ func HandlePasscode(issuer string, tlsClient http.Client, verbose bool) string {
213213
}
214214
return passcode
215215
}
216+
217+
func HandleTokenIntrospect(request url.Values, token string, tokenEndpoint string, tlsClient http.Client, verbose bool) string {
218+
request.Set("token", token)
219+
req, requestError := http.NewRequest("POST", tokenEndpoint, strings.NewReader(request.Encode()))
220+
if requestError != nil {
221+
log.Fatal(requestError)
222+
}
223+
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
224+
req.Header.Set("Accept", "application/json")
225+
req.Header.Set("User-Agent", agent)
226+
resp, clientError := tlsClient.Do(req)
227+
if clientError != nil {
228+
log.Fatal(clientError)
229+
}
230+
var result map[string]interface{}
231+
var resultString string
232+
json.NewDecoder(resp.Body).Decode(&result)
233+
if result != nil {
234+
jsonStr, marshalError := json.MarshalIndent(result, "", " ")
235+
if marshalError != nil {
236+
log.Fatal(marshalError)
237+
}
238+
resultString = string(jsonStr)
239+
if verbose {
240+
fmt.Println("Response from token introspect endpoint ")
241+
ShowJSonResponse(result, verbose)
242+
} else {
243+
fmt.Println(resultString)
244+
}
245+
}
246+
return resultString
247+
}

0 commit comments

Comments
 (0)