/** * @brief helper method to retrieve a user model of the currently authenticated user * * the function parses the authorization header of a request, * validates its format and ensures a proper session token is set. * it then takes the token and finds the user it belongs to. * * @param request a request * @return model of the currently authenticated user, taken from the storage * @throw kdbrest::exception::NoCurrentUserException * @throw kdbrest::exception::UserNotFoundException */ model::User AuthenticationApp::getCurrentUser (cppcms::http::request & request) { // authentication validation std::string headerAuthorization = request.http_authorization (); std::string token; if (headerAuthorization.empty ()) { // find token in get_parameters token = request.get (PARAM_TOKEN); if (token.empty ()) { throw exception::NoCurrentUserException (); } } else { if (!boost::starts_with (headerAuthorization, AUTH_HEADER_PREFIX)) { throw exception::NoCurrentUserException (); } token = headerAuthorization.substr (AUTH_HEADER_PREFIX.size ()); } /* request seems fine, lets build the jwt */ jwt_t * jwt; if (jwt_decode (&jwt, token.c_str (), reinterpret_cast<const unsigned char *> ( Config::instance ().getConfig ().get<std::string> ("jwt.encryption.secret").c_str ()), Config::instance ().getConfig ().get<std::string> ("jwt.encryption.secret").size ()) != 0) { throw exception::NoCurrentUserException (); } std::unique_ptr<jwt_t, void (*) (jwt_t *)> jwt_ptr (jwt, jwt_free); // check issuer and other grants if (std::string (jwt_get_grant (jwt_ptr.get (), "issuer")) != std::string (ELEKTRA_REST_AUTHENTICATION_JWT_ISSUER) || jwt_get_grant_int (jwt_ptr.get (), "expires") < std::time (NULL)) { throw exception::NoCurrentUserException (); } std::string username = std::string (jwt_get_grant (jwt_ptr.get (), "username")); if (username.empty ()) { throw exception::NoCurrentUserException (); } try { model::User user = service::StorageEngine::instance ().getUser (username); return user; } catch (exception::UserNotFoundException const & e) { throw exception::UserNotFoundException (); } }
/** * @brief validates the authorization header of a request() * * helper method that allows to validate whether a request contains a valid * session token or not. it checks for the authorization header, format and * validity of the token. * additionally the method can do checks on the authenticated users rank and * username (i.e. check for permissions or if is owner of something). * * @note if a rank and a username are given, it is sufficient that one of both matches the * requirement in order for the validation to succeed. * * @param request a request * @param response a response * @param rank optionally the rank of a user can be checked * @param orUser optionally the name of a user can be checked * @return true if an authentication is present and the authenticated user * matches all requirements, false otherwise */ bool AuthenticationApp::validateAuthentication (cppcms::http::request & request, cppcms::http::response & response, const int rank, const std::string orUser) { // authentication validation std::string headerAuthorization = request.http_authorization (); std::string token; if (headerAuthorization.empty ()) { // find token in get_parameters token = request.get (PARAM_TOKEN); if (token.empty ()) { RootApp::setUnauthorized (response, "Session token missing.", "NEED_AUTHENTICATION"); // send HTTP 401 return false; // not successful } } else { if (!boost::starts_with (headerAuthorization, AUTH_HEADER_PREFIX)) { RootApp::setUnauthorized (response, "Authentication header has wrong format.", "NEED_AUTHENTICATION"); return false; // not successful } token = headerAuthorization.substr (AUTH_HEADER_PREFIX.size ()); } /* request seems fine, so lets parse the token */ jwt_t * jwt; // decode it if (jwt_decode (&jwt, token.c_str (), reinterpret_cast<const unsigned char *> ( Config::instance ().getConfig ().get<std::string> ("jwt.encryption.secret").c_str ()), Config::instance ().getConfig ().get<std::string> ("jwt.encryption.secret").size ()) != 0) { RootApp::setUnauthorized (response, "Session token is invalid", "NEED_AUTHENTICATION"); // send HTTP 401 return false; } std::unique_ptr<jwt_t, void (*) (jwt_t *)> jwt_ptr (jwt, jwt_free); // check issuer and other grants if (std::string (jwt_get_grant (jwt_ptr.get (), "issuer")) != std::string (ELEKTRA_REST_AUTHENTICATION_JWT_ISSUER) || jwt_get_grant_int (jwt_ptr.get (), "expires") < std::time (NULL)) { RootApp::setUnauthorized (response, "Session token is invalid", "NEED_AUTHENTICATION"); // send HTTP 401 return false; } model::User currentUser = AuthenticationApp::getCurrentUser (request); if (currentUser.getRank () < rank && (orUser.empty () || orUser != currentUser.getUsername ())) { RootApp::setUnauthorized (response, "This action requires higher permissions.", "USER_INSUFFICIENT_PERMISSIONS"); return false; // not successful } return true; // authentication successful }
int jose_soft_verify(const char *jwt, jwa_t alg, jose_context_t *ctx) { assert (jwt); assert (ctx); int rc = -1; if (alg == HS256) { uint8_t *key; size_t k_len; assert (ctx->key_container[HS256].key); key = ctx->key_container[HS256].key; k_len = ctx->key_container[HS256].k_len; rc = hs256_soft_verify (jwt, key, k_len); } else if (alg == ES256) { assert (ctx->key_container[ES256].key); json_t *jwk = (json_t *)ctx->key_container[ES256].key; if (!json_is_object (jwk)) goto OUT; rc = es256_soft_verify (jwt, jwk); } else if (alg == NONE) { /* check to see if alg is really set to none */ json_t *h, *c; rc = jwt_decode (jwt, &h, &c); if (rc == 0) { const char *field = "alg"; json_t *alg_type = json_object_get(h, field); if (alg_type) { rc = strncmp (json_string_value (alg_type), "none", strlen("none")); } else rc = -2; json_decref (h); json_decref (c); } else { syslog (LOG_DEBUG, "JOSEC: Falied to decoded JWT"); } } OUT: return rc; }
int mosquitto_auth_unpwd_check(void *user_data, const char *username, const char *password) { jwt_t *jwt; #ifdef MQAP_DEBUG const char* val; int i_val; #endif time_t now; int iat; int exp; unsigned char key[32] = "012345678901234567890123456789AB"; if (username == NULL || password == NULL) { return MOSQ_ERR_AUTH; } #ifdef MQAP_DEBUG fprintf(stderr, "mosquitto_auth_unpwd_check: username=%s, password=%s\n", username, password); #endif if ( ! strcmp(username, "jwt") ) { time(&now); int status = jwt_decode(&jwt, password, key , sizeof(key)); if (( status == 0 ) && (jwt != NULL) ) { #ifdef MQAP_DEBUG fprintf(stderr, "mosquitto_auth_unpwd_check: password is a valid JWT token\n"); val = jwt_get_grant(jwt, "iss"); fprintf(stderr, "mosquitto_auth_unpwd_check: iss : %s\n", val); val = jwt_get_grant(jwt, "sub"); fprintf(stderr, "mosquitto_auth_unpwd_check: sub : %s\n", val); i_val = get_js_int(jwt->grants, "iat"); fprintf(stderr, "mosquitto_auth_unpwd_check: iat : %d\n", i_val); i_val = get_js_int(jwt->grants, "exp"); fprintf(stderr, "mosquitto_auth_unpwd_check: exp : %d\n", i_val); val = get_js_object(jwt->grants, "aud"); fprintf(stderr, "mosquitto_auth_unpwd_check: aud : %s\n", val); fprintf(stderr, "mosquitto_auth_unpwd_check: now : %d\n", (int)now); #endif iat = get_js_int(jwt->grants, "iat"); exp = get_js_int(jwt->grants, "exp"); if ( (now < iat) || (now > exp) ) { #ifdef MQAP_DEBUG fprintf(stderr, "mosquitto_auth_unpwd_check: token is expired\n"); #endif jwt_free(jwt); return MOSQ_ERR_AUTH; } // TODO add here some other controls about iss, sub, ... jwt_free(jwt); return MOSQ_ERR_SUCCESS; } else { #ifdef MQAP_DEBUG fprintf(stderr, "mosquitto_auth_unpwd_check: password is not a valid token %d\n", status); #endif } } return MOSQ_ERR_AUTH; }