Versions Compared

Key

  • This line was added.
  • This line was removed.
  • Formatting was changed.

...

See Setting up API Gateway for information on how to configure this using the Gateway configuration within the Console.

Session Resolver

Protecting access to these APIs is important - here is a copy from the default distribution of the session resolver setup for the internal gateway serving the Internal APIs

Code Block
languagejs
  "session": {
    "cookie.not.for.uri": "*.crl",
    "resolvers": ["io.ceptor.session.SessionResolverScript"],
    "cookie.no.cachecontrol.header.for": "*.crl|*.pdf",
    "http.cookiename": "sessionid",
    "https.cookiename": "sslsessionid",
    "cookie.path": "/",
    "sessionfixation.cookiename": "sslsessionid_sf",
    "cookie.use.httponly": true,
    "sessionfixation.addcookie": true,
    "sessionfixation.defense": true,
    "cookie.obfuscate": true,
    "cookie.use.domain": true,
    "cookie.samesite": "none",
    "resolve.script": "%{script:groovy}import dk.itp.security.passticket.PTException;\nimport io.undertow.util.Methods;\nimport io.undertow.util.Headers;\nimport io.undertow.util.HttpString;\n\nHttpString ACCESS_CONTROL_REQUEST_METHOD = HttpString.tryFromString(\"Access-Control-Request-Method\");\n\n// For useradmin API, just used the session ID in the query parameter, if present\nif (context.macro('%{REQUEST_PATH}').startsWith(\"/useradmin/\")) {\n    String sid = context.macro('%{query:session}');\n    if (sid?.trim()) {\n        try {\n            context.sessionId = new dk.itp.security.utils.UniqueId(sid);\n        } catch(Exception e) {\n            context.httpExchange.getResponseHeaders().add(io.undertow.util.HttpString.tryFromString(\"Access-Control-Allow-Origin\"), \"*\");\n            context.gateway.sendAndLogError(context, 401, \"Invalid session\", e)\n        }\n        return;\n    }\n}\n\nString authHeader = context.macro('%{requestheader:Authorization}');\n\nif (authHeader && authHeader.toLowerCase().startsWith(\"basic \")) {\n    try {\n        String sessionid = context.agent.getSessionFromTicket(54, authHeader.substring(6), context.config.gateway.segmentId, context.config.gateway.clusterId, context.gateway.getClientSourceIP(context), true);\n        if (sessionid) {\n            context.sessionId = new dk.itp.security.utils.UniqueId(sessionid);\n        }\n    } catch(PTException e) {\n        context.httpExchange.getResponseHeaders().add(io.undertow.util.HttpString.tryFromString(\"Access-Control-Allow-Origin\"), \"*\");\n        context.gateway.sendAndLogError(context, 401, \"Invalid credentials\", e)\n    }\n} else if (context.httpExchange.getRequestMethod() == Methods.OPTIONS && context.httpExchange.getRequestHeaders().contains(Headers.ORIGIN) && context.httpExchange.getRequestHeaders().contains(ACCESS_CONTROL_REQUEST_METHOD)) {\n    context.trace.trace(\"Allowing OPTIONS preflight request through without session\");\n} else {\n    context.httpExchange.getResponseHeaders().add(io.undertow.util.HttpString.tryFromString(\"Access-Control-Allow-Origin\"), \"*\");\n    context.httpExchange.getResponseHeaders().add(io.undertow.util.Headers.WWW_AUTHENTICATE, \"basic\");\n    context.gateway.sendAndLogError(context, 401, \"Authentication Required\", \"Basic auth required\")\n}"
  },

Here is the session resolver script as it looks in Groovy:

Code Block
import dk.itp.security.passticket.PTException;
import io.undertow.util.Methods;
import io.undertow.util.Headers;
import io.undertow.util.HttpString;

HttpString ACCESS_CONTROL_REQUEST_METHOD = HttpString.tryFromString("Access-Control-Request-Method");

// For useradmin API, just used the session ID in the query parameter, if present
if (context.macro('%{REQUEST_PATH}').startsWith("/useradmin/")) {
    String sid = context.macro('%{query:session}');
    if (sid?.trim()) {
        try {
            context.sessionId = new dk.itp.security.utils.UniqueId(sid);
        } catch(Exception e) {
            context.httpExchange.getResponseHeaders().add(io.undertow.util.HttpString.tryFromString("Access-Control-Allow-Origin"), "*");
            context.gateway.sendAndLogError(context, 401, "Invalid session", e)
        }
        return;
    }
}

String authHeader = context.macro('%{requestheader:Authorization}');

if (authHeader && authHeader.toLowerCase().startsWith("basic ")) {
    try {
        String sessionid = context.agent.getSessionFromTicket(54, authHeader.substring(6), context.config.gateway.segmentId, context.config.gateway.clusterId, context.gateway.getClientSourceIP(context), true);
        if (sessionid) {
            context.sessionId = new dk.itp.security.utils.UniqueId(sessionid);
        }
    } catch(PTException e) {
        context.httpExchange.getResponseHeaders().add(io.undertow.util.HttpString.tryFromString("Access-Control-Allow-Origin"), "*");
        context.gateway.sendAndLogError(context, 401, "Invalid credentials", e)
    }
} else if (context.httpExchange.getRequestMethod() == Methods.OPTIONS && context.httpExchange.getRequestHeaders().contains(Headers.ORIGIN) && context.httpExchange.getRequestHeaders().contains(ACCESS_CONTROL_REQUEST_METHOD)) {
    context.trace.trace("Allowing OPTIONS preflight request through without session");
} else {
    context.httpExchange.getResponseHeaders().add(io.undertow.util.HttpString.tryFromString("Access-Control-Allow-Origin"), "*");
    context.httpExchange.getResponseHeaders().add(io.undertow.util.Headers.WWW_AUTHENTICATE, "basic");
    context.gateway.sendAndLogError(context, 401, "Authentication Required", "Basic auth required")
}


Tip

The script uses basic authentication and expects same users as the ones who can access the console - for this to work, the authentication plugin; dk.itp.security.passticket.server.ConfigServerAuthenticationPlugin must be installed in the Session Controller.


Datastores

By default, APIs, Partners, Partner Applications and Developers (see Glossary for info) are stored in a Derby database, running on the local machine.

...