Skip to content

Commit d15d668

Browse files
committed
oauth: RFC8628
1 parent 5164edc commit d15d668

33 files changed

Lines changed: 2013 additions & 252 deletions

File tree

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
/*
2+
* libwebsockets - small server side websockets and web server implementation
3+
*
4+
* Copyright (C) 2010 - 2026 Andy Green <andy@warmcat.com>
5+
*
6+
* Permission is hereby granted, free of charge, to any person obtaining a copy
7+
* of this software and associated documentation files (the "Software"), to
8+
* deal in the Software without restriction, including without limitation the
9+
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10+
* sell copies of the Software, and to permit persons to whom the Software is
11+
* furnished to do so, subject to the following conditions:
12+
*
13+
* The above copyright notice and this permission notice shall be included in
14+
* all copies or substantial portions of the Software.
15+
*/
16+
17+
#ifndef _PROTOCOL_LWS_AUTH_DEVICE_CLIENT_H
18+
#define _PROTOCOL_LWS_AUTH_DEVICE_CLIENT_H
19+
20+
#define LWS_AUTH_DEVICE_CLIENT_ABI_VERSION 1
21+
22+
struct lws_auth_device_client_ops {
23+
uint32_t abi_version;
24+
25+
/* Called when authorization completes successfully to let the app proceed */
26+
void (*auth_success)(struct lws_vhost *vh, const char *logical_name, const char *access_token);
27+
28+
/* Called to start / stop flashing an LED or similar "pairing indication" */
29+
void (*pairing_indication)(struct lws_vhost *vh, const char *logical_name, int start);
30+
31+
/* Optional callback when code is retrieved */
32+
void (*display_code)(struct lws_vhost *vh, const char *logical_name, const char *user_code);
33+
34+
/* Optional callback to get a human-readable name for the device */
35+
const char *(*get_device_name)(struct lws_vhost *vh, const char *logical_name);
36+
};
37+
38+
struct lws_auth_device_client_api {
39+
uint32_t abi_version;
40+
41+
/* Start the auth flow against the given mixer URL for a specific logical device */
42+
void (*start_auth_flow)(struct lws_vhost *vh, const char *mixer_url, const char *logical_name);
43+
};
44+
45+
#endif

include/libwebsockets/lws-jwt-auth.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,16 @@ lws_jwt_auth_query_grant(struct lws_jwt_auth *ja, const char *service_name);
6969
LWS_VISIBLE LWS_EXTERN const char *
7070
lws_jwt_auth_get_sub(struct lws_jwt_auth *ja);
7171

72+
/**
73+
* lws_jwt_auth_get_did() - get the device id associated with the jwt (if any)
74+
*
75+
* \param ja: the jwt auth object
76+
*
77+
* Returns the device ID ("did" claim) from the jwt, or NULL.
78+
*/
79+
LWS_VISIBLE LWS_EXTERN const char *
80+
lws_jwt_auth_get_did(struct lws_jwt_auth *ja);
81+
7282
/**
7383
* lws_jwt_auth_get_uid() - Extract the native uid integer
7484
*

include/libwebsockets/lws-system.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ typedef enum {
4242
LWS_SYSBLOB_TYPE_MQTT_USERNAME,
4343
LWS_SYSBLOB_TYPE_MQTT_PASSWORD,
4444

45-
#if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4)
45+
#if defined(LWS_WITH_SECURE_STREAMS_AUTH_SIGV4) || defined(LWS_WITH_JOSE)
4646
/* extend 4 more auth blobs, each has 2 slots */
4747
LWS_SYSBLOB_TYPE_EXT_AUTH1,
4848
LWS_SYSBLOB_TYPE_EXT_AUTH2 = LWS_SYSBLOB_TYPE_EXT_AUTH1 + 2,

lib/core-net/client/connect.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,7 @@ lws_client_connect_via_info(const struct lws_client_connect_info *i)
545545

546546
#if defined(LWS_WITH_TLS)
547547
bail3:
548-
lwsl_wsi_info(wsi, "tls start fail");
548+
lwsl_wsi_err(wsi, "tls start fail");
549549
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS, "tls start fail");
550550

551551
if (i->pwsi)

lib/jose/jws/jwt-auth.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ struct lws_jwt_auth {
3131
uint64_t exp;
3232
char cookie_name[64];
3333
char sub[128];
34+
char did[128];
3435
uint32_t uid;
3536
};
3637

@@ -102,6 +103,7 @@ static const char * const auth_paths[] = {
102103
"sub",
103104
"email",
104105
"uid",
106+
"did",
105107
};
106108

107109
enum {
@@ -112,6 +114,7 @@ enum {
112114
JAP_SUB,
113115
JAP_EMAIL,
114116
JAP_UID,
117+
JAP_DID,
115118
};
116119

117120
static signed char
@@ -147,6 +150,8 @@ jwt_auth_lejp_cb(struct lejp_ctx *ctx, char reason)
147150
} else if (reason == LEJPCB_VAL_STR_CHUNK || reason == LEJPCB_VAL_STR_END) {
148151
if (ctx->path_match == JAP_SUB + 1 || ctx->path_match == JAP_EMAIL + 1) {
149152
lws_strncpy(pctx->ja->sub, ctx->buf, sizeof(pctx->ja->sub));
153+
} else if (ctx->path_match == JAP_DID + 1) {
154+
lws_strncpy(pctx->ja->did, ctx->buf, sizeof(pctx->ja->did));
150155
}
151156
}
152157

@@ -267,6 +272,14 @@ lws_jwt_auth_get_sub(struct lws_jwt_auth *ja)
267272
return ja->sub;
268273
}
269274

275+
const char *
276+
lws_jwt_auth_get_did(struct lws_jwt_auth *ja)
277+
{
278+
if (!ja || !ja->did[0])
279+
return NULL;
280+
return ja->did;
281+
}
282+
270283
uint32_t
271284
lws_jwt_auth_get_uid(struct lws_jwt_auth *ja)
272285
{

lib/roles/http/server/interceptor.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -269,10 +269,13 @@ lws_interceptor_check(struct lws *wsi, const struct lws_protocols *prot)
269269

270270
s = sizeof(buf);
271271
if (lws_jwt_get_http_cookie_validate_jwt(wsi, &ck, buf, &s)) {
272+
lwsl_notice("%s: JWT validation failed for cookie '%s'\n", __func__, vhd->cookie_name);
272273
lws_interceptor_inject_header(wsi, vhd, NULL);
273274
return vhd->always_pass ? 0 : 1;
274275
}
275276

277+
lwsl_notice("%s: JWT validation passed for cookie '%s', payload: %.*s\n", __func__, vhd->cookie_name, (int)s, buf);
278+
276279
cp = lws_json_simple_find(buf, s, "\"sub\":", &claim_len);
277280
if (!cp) {
278281
lwsl_vhost_notice(vhd->vhost, "%s: sub claim missing in JWT", __func__);

lib/roles/ws/server-ws.c

Lines changed: 0 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -397,13 +397,7 @@ lws_process_ws_upgrade2(struct lws *wsi)
397397
LWSIFR_SERVER | LWSIFR_P_ENCAP_H2,
398398
LRS_ESTABLISHED, &role_ops_ws);
399399

400-
/*
401-
* There should be no validity checking since we
402-
* are encapsulated in something else with its own
403-
* validity checking
404-
*/
405400

406-
lws_sul_cancel(&wsi->sul_validity);
407401
} else
408402
#endif
409403
{

lwsws/main.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,7 @@ context_creation(int argc, const char **argv)
173173
info.gid = (unsigned int)atoi(p);
174174

175175
/* Root monitor makes outbound TLS probes but skips user vhosts, force global TLS init */
176-
info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT;
176+
info.options |= LWS_SERVER_OPTION_DO_SSL_GLOBAL_INIT | LWS_SERVER_OPTION_VH_SKIP_PRIV_DROP;
177177
}
178178

179179
foreign_loops[0] = &loop;

minimal-examples-lowlevel/raw/minimal-raw-webrtc-camshow/minimal-raw-webrtc-camshow.c

Lines changed: 54 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,9 @@
1616

1717
#include "../../../plugins/protocol_lws_rtc_camera/protocol_lws_rtc_camera.h"
1818
#include "../../../plugins/protocol_lws_webrtc/protocol_lws_webrtc.h"
19+
#include "../../../include/libwebsockets/lws-auth-device-client.h"
20+
21+
static struct lws_auth_device_client_api *auth_api;
1922

2023
enum {
2124
LWS_SW_HEIGHT,
@@ -75,18 +78,13 @@ app_system_state_nf(lws_state_manager_t *mgr, lws_state_notify_link_t *link,
7578
return -1;
7679
}
7780

78-
if (!devices_copy)
79-
devices_copy = strdup(devs_list);
80-
81-
char *p = devices_copy;
82-
char *token;
83-
84-
while ((token = strsep(&p, ","))) {
85-
lwsl_notice("Attaching %s to WebRTC mixer\n", token);
86-
if (cam_ops->attach(vh, url, token, client_name, app_width, app_height))
87-
lwsl_err("Failed to queue attach for %s\n", token);
81+
if (!auth_api || !auth_api->start_auth_flow) {
82+
lwsl_err("auth_api not populated by plugin\n");
83+
return -1;
8884
}
8985

86+
auth_api->start_auth_flow(vh, url, "camshow");
87+
9088
break;
9189
}
9290
return 0;
@@ -118,6 +116,40 @@ set_clock(lws_usec_t us)
118116
return 0;
119117
}
120118

119+
static void start_app_attach(struct lws_vhost *vh, const char *logical_name, const char *access_token)
120+
{
121+
char *devices_copy_local = strdup(devs_list);
122+
char *p = devices_copy_local, *token;
123+
124+
while ((token = strsep(&p, ","))) {
125+
lwsl_notice("Attaching %s to WebRTC mixer\n", token);
126+
if (cam_ops->attach(vh, url, token, client_name, app_width, app_height, access_token))
127+
lwsl_err("Failed to queue attach for %s\n", token);
128+
}
129+
130+
free(devices_copy_local);
131+
}
132+
133+
static void pairing_indication(struct lws_vhost *vh, const char *logical_name, int start)
134+
{
135+
lwsl_notice("\n\n*** BLINK BLINK BLINK: Identify triggered by Admin for %s ***\n\n", logical_name);
136+
}
137+
138+
static void display_code(struct lws_vhost *vh, const char *logical_name, const char *user_code)
139+
{
140+
lwsl_notice("\n\n=======================================\n");
141+
lwsl_notice(" PAIRING REQUIRED FOR %s\n", logical_name);
142+
lwsl_notice(" User Code: %s\n", user_code);
143+
lwsl_notice("=======================================\n\n");
144+
}
145+
146+
static struct lws_auth_device_client_ops auth_ops = {
147+
.abi_version = LWS_AUTH_DEVICE_CLIENT_ABI_VERSION,
148+
.auth_success = start_app_attach,
149+
.pairing_indication = pairing_indication,
150+
.display_code = display_code,
151+
};
152+
121153
static const lws_system_ops_t system_ops = {
122154
.set_clock = set_clock,
123155
};
@@ -162,6 +194,11 @@ main(int argc, const char **argv)
162194

163195
info.system_ops = &system_ops;
164196

197+
static const struct lws_protocols protocols[] = {
198+
{ NULL, NULL, 0, 0, 0, NULL, 0 }
199+
};
200+
info.protocols = protocols;
201+
165202
/* Wire up cert trust bundle so wss:// connections can verify the peer */
166203
info.client_ssl_ca_filepath = "/etc/ssl/certs/ca-certificates.crt";
167204

@@ -201,7 +238,13 @@ main(int argc, const char **argv)
201238
static struct lws_protocol_vhost_options pvo_cam_status = { &pvo_ops, NULL, "status", "ok" };
202239
static struct lws_protocol_vhost_options pvo = { &pvo_cam_v4l2, &pvo_cam_status, "lws-rtc-camera", "" };
203240

204-
vinfo.pvo = &pvo;
241+
/* For lws-auth-device-client */
242+
static struct lws_protocol_vhost_options pvo_auth_api = { NULL, NULL, "lws-auth-client-api", (void *)&auth_api };
243+
static struct lws_protocol_vhost_options pvo_auth_ops = { &pvo_auth_api, NULL, "app-auth-ops", (void *)&auth_ops };
244+
static struct lws_protocol_vhost_options pvo_auth_status = { &pvo_auth_ops, NULL, "status", "ok" };
245+
static struct lws_protocol_vhost_options pvo_auth = { &pvo, &pvo_auth_status, "lws-auth-device-client", "" };
246+
247+
vinfo.pvo = &pvo_auth;
205248

206249
cx = lws_create_context(&info);
207250
if (!cx) {

plugins/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -123,6 +123,7 @@ if ((LWS_WITH_PLUGINS AND LWS_WITH_SHARED) OR LWS_WITH_PLUGINS_BUILTIN)
123123

124124
source_group("Headers Private" FILES ${PLUGIN_HDR})
125125
source_group("Sources" FILES ${PLUGIN_SRCS})
126+
message("CREATING PLUGIN ${PLUGIN_NAME}")
126127
add_library(${PLUGIN_NAME} SHARED ${PLUGIN_SRCS} ${PLUGIN_HDR})
127128
target_link_libraries(${PLUGIN_NAME} websockets_shared)
128129
add_dependencies(${PLUGIN_NAME} websockets_shared)

0 commit comments

Comments
 (0)