@@ -59,7 +59,25 @@ local function dump(o)
59
59
end
60
60
end
61
61
62
- function readAll (file )
62
+ -- Loops through array to find the given string.
63
+ -- items: array of strings
64
+ -- test_str: string to search for
65
+ local function contains (items , test_str )
66
+ for _ ,item in pairs (items ) do
67
+
68
+ -- strip whitespace
69
+ item = item :gsub (" %s+" , " " )
70
+ test_str = test_str :gsub (" %s+" , " " )
71
+
72
+ if item == test_str then
73
+ return true
74
+ end
75
+ end
76
+
77
+ return false
78
+ end
79
+
80
+ local function readAll (file )
63
81
log (" Reading file " .. file )
64
82
local f = assert (io.open (file , " rb" ))
65
83
local content = f :read (" *all" )
@@ -90,7 +108,6 @@ local function decodeJwt(authorizationHeader)
90
108
token .signature = headerFields [4 ]
91
109
token .signaturedecoded = base64 .decode (token .signature )
92
110
93
- log (' Authorization header: ' .. authorizationHeader )
94
111
log (' Decoded JWT header: ' .. dump (token .headerdecoded ))
95
112
log (' Decoded JWT payload: ' .. dump (token .payloaddecoded ))
96
113
@@ -137,11 +154,43 @@ local function issuerIsValid(token, expectedIssuer)
137
154
return token .payloaddecoded .iss == expectedIssuer
138
155
end
139
156
140
- local function audienceIsValid (token , expectedAudience )
141
- return token .payloaddecoded .aud == expectedAudience
157
+ -- Checks if the audience in the token is listed in the
158
+ -- OAUTH_AUDIENCE environment variable. Both the token audience
159
+ -- and the environment variable can contain multiple audience values,
160
+ -- separated by commas. Each value will be checked.
161
+ local function audienceIsValid (token , expectedAudienceParam )
162
+
163
+ -- Convert OAUTH_AUDIENCE environment variable to a table,
164
+ -- even if it contains only one value
165
+ local expectedAudiences = expectedAudienceParam
166
+ if type (expectedAudiences ) == " string" then
167
+ -- split multiple values using a space as the delimiter
168
+ expectedAudiences = core .tokenize (expectedAudienceParam , " " )
169
+ end
170
+
171
+ -- Convert 'aud' claim to a table, even if it contains only one value
172
+ local receivedAudiences = token .payloaddecoded .aud
173
+ if type (token .payloaddecoded .aud ) == " string" then
174
+ receivedAudiences = {}
175
+ receivedAudiences [1 ] = token .payloaddecoded .aud
176
+ end
177
+
178
+ for _ , receivedAudience in ipairs (receivedAudiences ) do
179
+ if contains (expectedAudiences , receivedAudience ) then
180
+ return true
181
+ end
182
+ end
183
+
184
+ return false
185
+ end
186
+
187
+ local function setVariablesFromPayload (txn , decodedPayload )
188
+ for key , value in pairs (decodedPayload ) do
189
+ txn :set_var (" txn.oauth." .. key , dump (value ))
190
+ end
142
191
end
143
192
144
- function jwtverify (txn )
193
+ local function jwtverify (txn )
145
194
local pem = config .publicKey
146
195
local issuer = config .issuer
147
196
local audience = config .audience
@@ -155,6 +204,9 @@ function jwtverify(txn)
155
204
goto out
156
205
end
157
206
207
+ -- Set an HAProxy variable for each field in the token payload
208
+ setVariablesFromPayload (txn , token .payloaddecoded )
209
+
158
210
-- 2. Verify the signature algorithm is supported (HS256, HS512, RS256)
159
211
if algorithmIsValid (token ) == false then
160
212
log (" Algorithm not valid." )
@@ -197,13 +249,6 @@ function jwtverify(txn)
197
249
goto out
198
250
end
199
251
200
- -- 7. Add scopes to variable
201
- if token .payloaddecoded .scope ~= nil then
202
- txn .set_var (txn , " txn.oauth_scopes" , token .payloaddecoded .scope )
203
- else
204
- txn .set_var (txn , " txn.oauth_scopes" , " " )
205
- end
206
-
207
252
-- 8. Set authorized variable
208
253
log (" req.authorized = true" )
209
254
txn .set_var (txn , " txn.authorized" , true )
@@ -220,20 +265,20 @@ end
220
265
-- Called after the configuration is parsed.
221
266
-- Loads the OAuth public key for validating the JWT signature.
222
267
core .register_init (function ()
223
- config .issuer = os.getenv (" OAUTH_ISSUER" )
224
- config .audience = os.getenv (" OAUTH_AUDIENCE" )
225
-
226
- -- when using an RS256 signature
227
- local publicKeyPath = os.getenv (" OAUTH_PUBKEY_PATH" )
228
- local pem = readAll (publicKeyPath )
229
- config .publicKey = pem
230
-
231
- -- when using an HS256 or HS512 signature
232
- config .hmacSecret = os.getenv (" OAUTH_HMAC_SECRET" )
233
-
234
- log (" PublicKeyPath: " .. publicKeyPath )
235
- log (" Issuer: " .. (config .issuer or " <none>" ))
236
- log (" Audience: " .. (config .audience or " <none>" ))
268
+ config .issuer = os.getenv (" OAUTH_ISSUER" )
269
+ config .audience = os.getenv (" OAUTH_AUDIENCE" )
270
+
271
+ -- when using an RS256 signature
272
+ local publicKeyPath = os.getenv (" OAUTH_PUBKEY_PATH" )
273
+ local pem = readAll (publicKeyPath )
274
+ config .publicKey = pem
275
+
276
+ -- when using an HS256 or HS512 signature
277
+ config .hmacSecret = os.getenv (" OAUTH_HMAC_SECRET" )
278
+
279
+ log (" PublicKeyPath: " .. publicKeyPath )
280
+ log (" Issuer: " .. (config .issuer or " <none>" ))
281
+ log (" Audience: " .. (config .audience or " <none>" ))
237
282
end )
238
283
239
284
-- Called on a request.
0 commit comments