bsw/jbe@1309: if not request.is_post() then bsw/jbe@1309: return execute.view { module = "index", view = "405" } bsw/jbe@1309: end bsw/jbe@1309: bsw/jbe@1309: slot.set_layout(nil, "application/json;charset=UTF-8") bsw/jbe@1309: bsw/jbe@1309: local r = json.object() bsw/jbe@1309: bsw/jbe@1309: local function error_result(error_code, error_description) bsw/jbe@1309: -- TODO special HTTP status codes for some errors? bsw/jbe@1309: request.set_status("400 Bad Request") bsw/jbe@1309: slot.put_into("data", json.export{ bsw/jbe@1309: error = error_code, bsw/jbe@1309: error_description = error_description bsw/jbe@1309: }) bsw/jbe@1309: end bsw/jbe@1309: bsw/jbe@1309: local client_id = param.get("client_id") bsw/jbe@1309: local flow = param.get("flow") bsw/jbe@1309: local scope = param.get("scope") bsw/jbe@1309: bsw/jbe@1309: if flow ~= "code" and flow ~= "token" then bsw/jbe@1309: return error_result("invalid_request", "invalid flow") bsw/jbe@1309: end bsw/jbe@1309: bsw/jbe@1309: local domain bsw/jbe@1309: bsw/jbe@1309: if client_id then bsw/jbe@1309: domain = string.match(client_id, "^dynamic:([a-z0-9.-]+)$") bsw/jbe@1309: if not domain then bsw/jbe@1309: return error_result("invalid_client", "invalid client_id (use lower case host name prefixed with 'dynamic:')") bsw/jbe@1309: end bsw/jbe@1309: end bsw/jbe@1309: bsw/jbe@1309: local cert_ca = request.get_header("X-LiquidFeedback-CA") bsw/jbe@1309: local cert_distinguished_name = request.get_header("X-SSL-DN") bsw/jbe@1309: local cert_common_name bsw/jbe@1309: bsw/jbe@1309: if cert_distinguished_name then bsw/jbe@1309: cert_common_name = string.match(cert_distinguished_name, "%f[^/\0]CN=([A-Za-z0-9_.-]+)%f[/\0]") bsw/jbe@1309: if not cert_common_name then bsw/jbe@1309: return error_result("invalid_client", "CN in X.509 certificate invalid") bsw/jbe@1309: end bsw/jbe@1309: else bsw/jbe@1309: return error_result("invalid_client", "X.509 client authorization missing") bsw/jbe@1309: end bsw/jbe@1309: bsw/jbe@1309: if cert_ca ~= "public" then bsw/jbe@1309: return error_result("invalid_client", "X.509 certificate not signed by publicly trusted certificate authority or wrong endpoint used") bsw/jbe@1309: end bsw/jbe@1309: bsw/jbe@1309: if domain then bsw/jbe@1309: if domain ~= cert_common_name then bsw/jbe@1309: return error_result("invalid_grant", "CN in X.509 certificate incorrect") bsw/jbe@1309: end bsw/jbe@1309: else bsw/jbe@1309: domain = cert_common_name bsw/jbe@1309: end bsw/jbe@1309: bsw/jbe@1309: local redirect_uri = "https://" .. domain .. "/" .. config.oauth2.endpoint_magic bsw/jbe@1309: bsw/jbe@1309: local expiry = db:query({ "SELECT now() + (? || 'sec')::interval AS expiry", config.oauth2.dynamic_registration_lifetime }, "object").expiry bsw/jbe@1309: bsw/jbe@1309: for s in string.gmatch(scope, "[^ ]+") do bsw/jbe@1309: local dynamic_application_scope = DynamicApplicationScope:new() bsw/jbe@1309: dynamic_application_scope.redirect_uri = redirect_uri bsw/jbe@1309: dynamic_application_scope.flow = flow bsw/jbe@1309: dynamic_application_scope.scope = s bsw/jbe@1309: dynamic_application_scope.expiry = expiry bsw/jbe@1309: dynamic_application_scope:upsert_mode() bsw/jbe@1309: dynamic_application_scope:save() bsw/jbe@1309: end bsw/jbe@1309: bsw/jbe@1309: r.client_id = "dynamic:" .. domain bsw/jbe@1309: r.expires_in = config.oauth2.dynamic_registration_lifetime bsw/jbe@1309: bsw/jbe@1309: slot.put_into("data", json.export(r))