Browse Source

now the tls certificate is matched with the JWT signature

master
Nicolas Massé 8 years ago
parent
commit
bedd42ed5e
  1. 100
      nginx.env.conf
  2. 28
      tests/sign.sh

100
nginx.env.conf

@ -162,6 +162,7 @@ http {
}),
headers = {
["Content-Type"] = "application/x-www-form-urlencoded",
["Host"] = ngx.var.host
},
method = "POST",
ssl_verify = false
@ -182,7 +183,8 @@ http {
clientId = client_id
},
headers = {
["Authorization"] = "Bearer " .. access_token
["Authorization"] = "Bearer " .. access_token,
["Host"] = ngx.var.host
},
method = "GET",
ssl_verify = false
@ -208,7 +210,8 @@ http {
res, err = httpc:request_uri("http://${SSO_SERVICE_HOSTNAME}/auth/admin/realms/"..realm.."/clients/" .. client_id_rhssoid .. "/certificates/jwt.credential", {
method = "GET",
headers = {
["Authorization"] = "Bearer " .. access_token
["Authorization"] = "Bearer " .. access_token,
["Host"] = ngx.var.host
},
ssl_verify = false
})
@ -251,7 +254,8 @@ http {
body = body,
headers = {
["Authorization"] = "Bearer " .. access_token,
["Content-Type"] = content_type
["Content-Type"] = content_type,
["Host"] = ngx.var.host
},
ssl_verify = false
})
@ -274,21 +278,95 @@ http {
location ~ ^/auth/realms/(${SSO_REALMS})/protocol/openid-connect/token$ {
access_by_lua_block {
ngx.log(ngx.INFO, "VERIFY: ", ngx.var.ssl_client_verify)
if ngx.var.ssl_client_verify ~= "SUCCESS" then
if ngx.var.ssl_client_verify ~= "SUCCESS" or not ngx.var.ssl_client_raw_cert then
ngx.status = ngx.HTTP_FORBIDDEN
ngx.header['Content-Type'] = 'application/json'
ngx.say('{"error":"invalid_request","error_description":"You need to authenticate using an SSL/TLS Client Certificate."}')
ngx.exit(ngx.HTTP_OK)
end
ngx.log(ngx.ERR, "Authenticated Client : ", ngx.var.ssl_client_s_dn)
ngx.log(ngx.INFO, "Authenticated Client : ", ngx.var.ssl_client_s_dn)
}
# Beware: no slash at the end of the proxy_pass directive since we don't want to rewrite URLs
proxy_pass http://${SSO_SERVICE_HOSTNAME};
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
content_by_lua_block {
local jwt = require "resty.jwt"
local http = require "resty.http"
ngx.req.read_body()
local form, err = ngx.req.get_post_args()
if not form then
ngx.status = ngx.HTTP_BAD_REQUEST
ngx.header['Content-Type'] = 'application/json'
ngx.say('{"error":"invalid_request","error_description":"You need to pass the token request arguments in the post body."}')
ngx.exit(ngx.HTTP_OK)
end
local client_assertion = form['client_assertion']
local client_assertion_type = form['client_assertion_type']
if not client_assertion_type or client_assertion_type ~= "urn:ietf:params:oauth:client-assertion-type:jwt-bearer" then
ngx.status = ngx.HTTP_BAD_REQUEST
ngx.header['Content-Type'] = 'application/json'
ngx.say('{"error":"invalid_request","error_description":"Only JWT is allowed for client authentication. See RFC 7523."}')
ngx.exit(ngx.HTTP_OK)
end
if not client_assertion then
ngx.status = ngx.HTTP_BAD_REQUEST
ngx.header['Content-Type'] = 'application/json'
ngx.say('{"error":"invalid_request","error_description":"No client_assertion found."}')
ngx.exit(ngx.HTTP_OK)
end
local certificate = ngx.var.ssl_client_raw_cert
local jwt_obj = jwt:load_jwt(client_assertion)
if not jwt_obj.valid then
ngx.status = ngx.HTTP_BAD_REQUEST
ngx.header['Content-Type'] = 'application/json'
ngx.say('{"error":"invalid_request","error_description":"client_assertion is not a valid JWT."}')
ngx.exit(ngx.HTTP_OK)
end
if jwt_obj.header.alg ~= "RS256" then
ngx.status = ngx.HTTP_BAD_REQUEST
ngx.header['Content-Type'] = 'application/json'
ngx.say('{"error":"invalid_request","error_description":"client_assertion must be signed using the RS256 algorithm."}')
ngx.exit(ngx.HTTP_OK)
end
jwt_obj = jwt:verify_jwt_obj(certificate, jwt_obj, {})
if not jwt_obj.verified then
ngx.status = ngx.HTTP_FORBIDDEN
ngx.header['Content-Type'] = 'application/json'
ngx.say('{"error":"invalid_request","error_description":"client_assertion signature cannot be verified."}')
ngx.log(ngx.WARN, "JWT validation error: ", jwt_obj.reason)
ngx.exit(ngx.HTTP_OK)
end
local httpc = http.new()
local body = ngx.req.get_body_data()
local headers = {}
local h = ngx.req.get_headers()
for k, v in pairs(h) do
headers[k] = v
end
local res, err = httpc:request_uri("http://${SSO_SERVICE_HOSTNAME}" .. ngx.var.uri, {
body = body,
headers = headers,
method = "POST",
ssl_verify = false
})
if not res then
ngx.status = ngx.HTTP_INTERNAL_SERVER_ERROR
ngx.header['Content-Type'] = 'application/json'
ngx.say('{"error":"server_error","error_description":"Could not get a response from RH-SSO."}')
ngx.exit(ngx.HTTP_OK)
end
ngx.status = res.status;
ngx.header['Content-Type'] = res.headers['Content-Type']
ngx.say(res.body);
}
}
location ~ ^/.* {

28
tests/sign.sh

@ -0,0 +1,28 @@
#!/bin/bash
if [ "$#" -ne 2 ]; then
echo "Usage: $0 subject audience"
exit 1
fi
ISSUER="$1"
SUBJECT="$1"
AUDIENCE="$2"
EXPIRATION=$(date -v+1d "+%s")
ISSUED_AT=$(date "+%s")
NOT_BEFORE=$(date -v-1H "+%s")
TOKENID=$(openssl rand -hex 8)
jwt -claim "iss=$ISSUER" \
-claim "sub=$SUBJECT" \
-claim "aud=$AUDIENCE" \
-claim "exp=$EXPIRATION" \
-claim "iat=$ISSUED_AT" \
-claim "nbf=$NOT_BEFORE" \
-claim "jti=$TOKENID" \
-sign + \
-key "client.key" \
-alg "RS256"
Loading…
Cancel
Save