Merge pull request #7710 from JimMoen/add-authn-authz-zh_CN-desc

add authn & authz zh_CN i18n support
This commit is contained in:
JianBo He 2022-04-22 11:57:25 +08:00 committed by GitHub
commit 56b3007d59
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
32 changed files with 2061 additions and 306 deletions

View File

@ -0,0 +1,228 @@
emqx_authn_api {
authentication_get {
desc {
en: """List authenticators for global authentication"""
zh: """列出全局认证链上的认证器信息"""
}
}
authentication_post {
desc {
en: """Create authenticator for global authentication"""
zh: """为全局认证链创建认证器信息"""
}
}
authentication_id_get {
desc {
en: """Get authenticator from global authentication chain"""
zh: """获取全局认证链上指定的认证器信息"""
}
}
authentication_id_put {
desc {
en: """Update authenticator from global authentication chain"""
zh: """更新全局认证链上指定的认证器"""
}
}
authentication_id_delete {
desc {
en: """Delete authenticator from global authentication chain"""
zh: """删除全局认证链上指定的认证器信息"""
}
}
authentication_id_status_get {
desc {
en: """Get authenticator status from global authentication chain"""
zh: """获取全局认证链上指定的认证器状态"""
}
}
listeners_listener_id_authentication_get {
desc {
en: """List authenticators for listener authentication"""
zh: """列出监听器上的认证器信息"""
}
}
listeners_listener_id_authentication_post {
desc {
en: """Create authenticator for listener authentication"""
zh: """在指定的监听器上创建认证器"""
}
}
listeners_listener_id_authentication_id_get {
desc {
en: """Get authenticator from listener authentication chain"""
zh: """获取监听器上指定的认证器信息"""
}
}
listeners_listener_id_authentication_id_put {
desc {
en: """Update authenticator from listener authentication chain"""
zh: """更新监听器上指定的认证器"""
}
}
listeners_listener_id_authentication_id_delete {
desc {
en: """Delete authenticator from listener authentication chain"""
zh: """删除监听器上指定的认证器"""
}
}
listeners_listener_id_authentication_id_status_get {
desc {
en: """Get authenticator status from listener authentication chain"""
zh: """获取监听器上指定的认证器状态"""
}
}
authentication_id_move_post {
desc {
en: """Move authenticator in global authentication chain"""
zh: """移动全局认证链上认证器的顺序"""
}
}
listeners_listener_id_authentication_id_move_post {
desc {
en: """Move authenticator in listener authentication chain"""
zh: """移动监听器上认证器的顺序"""
}
}
authentication_id_import_users_post {
desc {
en: """Import users into authenticator in global authentication chain"""
zh: """为全局认证链上的认证器导入用户数据"""
}
}
listeners_listener_id_authentication_id_import_users_post {
desc {
en: """Import users into authenticator in listener authentication chain"""
zh: """为监听器上的认证器导入用户数据"""
}
}
authentication_id_users_post {
desc {
en: """Create users for authenticator in global authentication chain"""
zh: """为全局认证链上的认证器创建用户数据"""
}
}
authentication_id_users_get {
desc {
en: """List users in authenticator in global authentication chain"""
zh: """获取全局认证链上指定的认证器中的用户数据"""
}
}
listeners_listener_id_authentication_id_users_post {
desc {
en: """Create users for authenticator in listener authentication chain"""
zh: """更新指定监听器上认证器中的用户数据"""
}
}
listeners_listener_id_authentication_id_users_get {
desc {
en: """List users in authenticator in listener authentication chain"""
zh: """列出指定监听器上认证器中的用户数据"""
}
}
authentication_id_users_user_id_get {
desc {
en: """Get user from authenticator in global authentication chain"""
zh: """获取指定监听器上认证器中指定的用户数据"""
}
}
authentication_id_users_user_id_put {
desc {
en: """Update user in authenticator in global authentication chain"""
zh: """为指定监听器上认证器添加用户数据"""
}
}
authentication_id_users_user_id_delete {
desc {
en: """Update user in authenticator in global authentication chain"""
zh: """更新指定监听器上认证器中的用户数据"""
}
}
listeners_listener_id_authentication_id_users_user_id_get {
desc {
en: """Get user from authenticator in listener authentication chain"""
zh: """获取指定监听器上认证器中指定的用户数据"""
}
}
listeners_listener_id_authentication_id_users_user_id_put {
desc {
en: """Update user in authenticator in listener authentication chain"""
zh: """更新指定监听器上认证器中的用户数据"""
}
}
listeners_listener_id_authentication_id_users_user_id_delete {
desc {
en: """Delete user in authenticator in listener authentication chain"""
zh: """删除指定监听器上认证器中的用户数据"""
}
}
param_auth_id {
desc {
en: """Authenticator ID"""
zh: """认证器 ID"""
}
}
param_listener_id {
desc {
en: """Listener ID"""
zh: """监听器 ID"""
}
}
param_user_id {
desc {
en: """User ID"""
zh: """用户 ID"""
}
}
like_username {
desc {
en: """Fuzzy search username"""
zh: """使用用户名模糊查询"""
}
label {
en: """like_username"""
zh: """模糊用户名"""
}
}
like_clientid {
desc {
en: """Fuzzy search clientid"""
zh: """使用客户端标识符模糊查询"""
}
label {
en: """like_clientid"""
zh: """模糊用户名"""
}
}
}

View File

@ -0,0 +1,89 @@
emqx_authn_http {
get {
desc {
en: """Settings for HTTP-based authentication (GET)."""
zh: """基于 HTTP 的认证请求 (GET)"""
}
label: {
en: """get"""
zh: """get"""
}
}
post {
desc {
en: """Settings for HTTP-based authentication (POST)."""
zh: """基于 HTTP 的认证请求 (POST)"""
}
label: {
en: """post"""
zh: """post"""
}
}
method {
desc {
en: """HTTP method."""
zh: """HTTP 请求方法"""
}
label: {
en: """method"""
zh: """请求方法"""
}
}
url {
desc {
en: """URL of the auth server."""
zh: """认证服务器地址"""
}
label: {
en: """url"""
zh: """统一资源定位符"""
}
}
headers {
desc {
en: """List of HTTP headers."""
zh: """HTTP 请求头列表"""
}
label: {
en: """headers"""
zh: """请求头"""
}
}
headers_no_content_type {
desc {
en: """List of HTTP headers. (without <code>content-type</code>)"""
zh: """HTTP 请求头列表(无 <code>content-type</code>)"""
}
label: {
en: """headers_no_content_type"""
zh: """无content_type的请求头"""
}
}
body {
desc {
en: """Body of the HTTP request."""
zh: """HTTP 请求体"""
}
label: {
en: """body"""
zh: """请求体"""
}
}
request_timeout {
desc {
en: """HTTP request timeout"""
zh: """HTTP 请求超时时长"""
}
label: {
en: """request_timeout"""
zh: """请求超时时间"""
}
}
}

View File

@ -0,0 +1,155 @@
emqx_authn_schema {
enable {
desc {
en: """Set to <code>true</code> or <code>false</code> to disable this auth provider"""
zh: """设为 <code>true</code> 或 <code>false</code> 以启用或禁用此认证数据源"""
}
label: {
en: """enable"""
zh: """启用"""
}
}
mechanism {
desc {
en: """Authentication mechanism."""
zh: """认证机制"""
}
label: {
en: """mechanism"""
zh: """机制"""
}
}
backend {
desc {
en: """Backend type."""
zh: """后端类型"""
}
label: {
en: """backend"""
zh: """后端"""
}
}
metrics {
desc {
en: """The metrics of the resource"""
zh: """统计指标"""
}
label: {
en: """metrics"""
zh: """指标"""
}
}
node_metrics {
desc {
en: """The metrics of the resource for each node"""
zh: """每个节点上资源的统计指标"""
}
label: {
en: """node_metrics"""
zh: """节点指标"""
}
}
status {
desc {
en: """The status of the resource"""
zh: """资源状态"""
}
label: {
en: """status"""
zh: """状态"""
}
}
node_status {
desc {
en: """The status of the resource for each node"""
zh: """每个节点上资源的状态"""
}
label: {
en: """node_status"""
zh: """节点状态"""
}
}
matched {
desc {
en: """Count of this resource is queried"""
zh: """请求命中次数"""
}
label: {
en: """matched"""
zh: """已命中"""
}
}
success {
desc {
en: """Count of query success"""
zh: """请求成功次数"""
}
label: {
en: """success"""
zh: """成功"""
}
}
failed {
desc {
en: """Count of query failed"""
zh: """请求失败次数"""
}
label: {
en: """failed"""
zh: """失败"""
}
}
rate {
desc {
en: """The rate of matched, times/second"""
zh: """命中速率,单位: 次/秒"""
}
label: {
en: """rate"""
zh: """速率"""
}
}
rate_max {
desc {
en: """The max rate of matched, times/second"""
zh: """最大命中速率,单位: 次/秒"""
}
label: {
en: """rate_max"""
zh: """最大速率"""
}
}
rate_last5m {
desc {
en: """The average rate of matched in the last 5 minutes, times/second"""
zh: """5分钟内平均命中速率单位 次/秒"""
}
label: {
en: """rate_last5m"""
zh: """5分钟内速率"""
}
}
node {
desc {
en: """The node name"""
zh: """节点名"""
}
label: {
en: """node"""
zh: """节点"""
}
}
}

View File

@ -0,0 +1,232 @@
emqx_authn_jwt {
use_jwks {
desc {
en: """jwks flag"""
zh: """jwks 状态"""
}
label {
en: """use_jwks"""
zh: """使用jwks"""
}
}
algorithm {
desc {
en: """Signing algorithm."""
zh: """签名算法"""
}
label {
en: """algorithm"""
zh: """算法"""
}
}
certificate {
desc {
en: """The certificate used for signing the token."""
zh: """用于签名token的证书"""
}
label {
en: """certificate"""
zh: """证书"""
}
}
secret_base64_encoded {
desc {
en: """Enable/disable base64 encoding of the secret."""
zh: """启用/关闭私匙 base64 编码"""
}
label {
en: """secret_base64_encoded"""
zh: """密钥 base64 编码"""
}
}
secret {
desc {
en: """The key to verify the JWT Token using HMAC algorithm."""
zh: """使用对称加密的算法"""
}
label {
en: """secret"""
zh: """secret"""
}
}
endpoint {
desc {
en: """JWKs endpoint"""
zh: """JWKs endpoint"""
}
label {
en: """endpoint"""
zh: """endpoint"""
}
}
refresh_interval {
desc {
en: """JWKs refresh interval"""
zh: """JWKs 更新间隔"""
}
label {
en: """refresh_interval"""
zh: """更新间隔"""
}
}
cacertfile {
desc {
en: """Path to the SSL CA certificate file."""
zh: """SSL CA 证书公钥文件路径"""
}
label {
en: """cacertfile"""
zh: """CA 证书文件"""
}
}
certfile {
desc {
en: """Path to the SSL certificate file."""
zh: """证书文件路径"""
}
label {
en: """certfile"""
zh: """证书文件"""
}
}
keyfile {
desc {
en: """Path to the SSL secret key file."""
zh: """SSL 私钥文件路径"""
}
label {
en: """keyfile"""
zh: """私钥文件"""
}
}
verify {
desc {
en: """Enable or disable SSL peer verification."""
zh: """指定握手过程中是否校验客户端"""
}
label {
en: """verify"""
zh: """verify"""
}
}
server_name_indication {
desc {
en: """SSL SNI (Server Name Indication)"""
zh: """SSL SNI (服务器名称指示)"""
}
label {
en: """server_name_indication"""
zh: """服务器名称指示"""
}
}
verify_claims {
desc {
en: """The list of claims to verify."""
zh: """The list of claims to verify."""
}
label {
en: """verify_claims"""
zh: """verify_claims"""
}
}
pool_size {
desc {
en: """JWKs connection count"""
zh: """JWKs 连接数量"""
}
label {
en: """pool_size"""
zh: """pool_size"""
}
}
ssl {
desc {
en: """SSL options."""
zh: """SSL 选项"""
}
label {
en: """ssl"""
zh: """ssl"""
}
}
enable {
desc {
en: """Enable/disable SSL."""
zh: """启用/禁用 SSL"""
}
label {
en: """enable"""
zh: """启用"""
}
}
hmac-based {
desc {
en: """Settings for HMAC-based token signing algorithm."""
zh: """HMAC-based token 签名配置"""
}
label {
en: """hmac-based"""
zh: """hmac-based"""
}
}
public-key {
desc {
en: """Settings for public key-based token signing algorithm."""
zh: """公钥token签名配置"""
}
label {
en: """public-key"""
zh: """public-key"""
}
}
jwks {
desc {
en: """Settings for a signing using JSON Web Key Set (JWKs)."""
zh: """JWks 签名配置"""
}
label {
en: """jwks"""
zh: """jwks"""
}
}
ssl_disable {
desc {
en: """SSL disabled"""
zh: """SSL 关闭"""
}
label {
en: """ssl_disable"""
zh: """关闭SSL"""
}
}
ssl_enable {
desc {
en: """SSL configuration."""
zh: """SSL 配置"""
}
label {
en: """ssl_enable"""
zh: """启用SSL"""
}
}
}

View File

@ -0,0 +1,23 @@
emqx_authn_mnesia {
authentication {
desc {
en: """Configuration for authentication using the built-in database."""
zh: """内置数据库认证配置"""
}
label: {
en: """authentication"""
zh: """认证配置"""
}
}
user_id_type {
desc {
en: """Authenticate by Client ID or Username."""
zh: """认证类型,基于 Client ID 或 Username"""
}
label: {
en: """user_id_type"""
zh: """用户标识类型"""
}
}
}

View File

@ -0,0 +1,99 @@
emqx_authn_mongodb {
standalone {
desc {
en: """Configuration for a standalone MongoDB instance."""
zh: """MongoDB 单节点认证配置"""
}
label: {
en: """standalone"""
zh: """standalone 模式"""
}
}
replica-set {
desc {
en: """Configuration for a replica set."""
zh: """MongoDB replica set 模式认证配置"""
}
label: {
en: """replica-set"""
zh: """replica-set 模式"""
}
}
sharded-cluster {
desc {
en: """Configuration for a sharded cluster."""
zh: """MongoDB sharded cluster 模式认证配置"""
}
label: {
en: """sharded-cluster"""
zh: """sharded-cluster 模式"""
}
}
collection {
desc {
en: """Collection used to store authentication data."""
zh: """认证数据集名称"""
}
label: {
en: """collection"""
zh: """数据集"""
}
}
selector {
desc {
en: """
Statement that is executed during the authentication process.
Commands can support following wildcards:\n
- `${username}`: substituted with client's username\n
- `${clientid}`: substituted with the clientid
"""
zh: """
认证过程中所使用的查询命令。
查询命令支持如下占位符:
- `${username}`: 代替客户端的用户名
- `${clientid}`: 代替客户端的客户端标识符
"""
}
label: {
en: """selector"""
zh: """认证查询"""
}
}
password_hash_field {
desc {
en: """Document field that contains password hash."""
zh: """数据文档中的密码散列值"""
}
label: {
en: """password_hash_field"""
zh: """密码散列字段"""
}
}
salt_field {
desc {
en: """Document field that contains the password salt."""
zh: """数据文档中的密码加盐"""
}
label: {
en: """salt_field"""
zh: """加盐字段"""
}
}
is_superuser_field {
desc {
en: """Document field that defines if the user has superuser privileges."""
zh: """数据文档中的超级用户权限记录"""
}
label: {
en: """is_superuser_field"""
zh: """超级用户字段"""
}
}
}

View File

@ -0,0 +1,34 @@
emqx_authn_mysql {
authentication {
desc {
en: """Configuration for authentication using MySQL database."""
zh: """MySQL 认证配置"""
}
label: {
en: """authentication"""
zh: """认证配置"""
}
}
query {
desc {
en: """SQL query used to lookup client data."""
zh: """客户端数据查询 SQL 语句"""
}
label: {
en: """query"""
zh: """请求"""
}
}
query_timeout {
dsec {
en: """Timeout for the SQL query."""
zh: """SQL 查询超时时长"""
}
label: {
en: """query_timeout"""
zh: """请求超时"""
}
}
}

View File

@ -0,0 +1,23 @@
emqx_authn_pgsql {
authentication {
desc {
en: """Configuration for PostgreSQL authentication backend."""
zh: """PostgreSQL 认证配置"""
}
label: {
en: """authentication"""
zh: """认证配置"""
}
}
query {
desc {
en: """`SQL` query for looking up authentication data."""
zh: """客户端数据查询 SQL 语句"""
}
label: {
en: """query"""
zh: """请求"""
}
}
}

View File

@ -0,0 +1,45 @@
emqx_authn_redis {
standalone {
desc {
en: """Configuration for a standalone Redis instance."""
zh: """Redis 单节点认证配置"""
}
label: {
en: """standalone"""
zh: """standalone"""
}
}
cluster {
desc {
en: """Configuration for a Redis cluster."""
zh: """Redis 集群模式认证配置"""
}
label: {
en: """cluster"""
zh: """cluster"""
}
}
sentinel {
desc {
en: """Configuration for a Redis Sentinel."""
zh: """Redis 哨兵模式认证配置"""
}
label: {
en: """sentinel"""
zh: """sentinel"""
}
}
cmd {
desc {
en: """Database query used to retrieve authentication data."""
zh: """Redis 认证数据查询语句"""
}
label: {
en: """cmd"""
zh: """查询命令"""
}
}
}

View File

@ -18,11 +18,11 @@
-behaviour(minirest_api). -behaviour(minirest_api).
-include_lib("typerefl/include/types.hrl").
-include("emqx_authn.hrl"). -include("emqx_authn.hrl").
-include_lib("emqx/include/emqx_placeholder.hrl").
-include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/logger.hrl").
-include_lib("emqx/include/emqx_placeholder.hrl").
-include_lib("emqx/include/emqx_authentication.hrl"). -include_lib("emqx/include/emqx_authentication.hrl").
-include_lib("hocon/include/hoconsc.hrl").
-import(hoconsc, [mk/2, ref/1, ref/2]). -import(hoconsc, [mk/2, ref/1, ref/2]).
-import(emqx_dashboard_swagger, [error_codes/2]). -import(emqx_dashboard_swagger, [error_codes/2]).
@ -154,7 +154,7 @@ schema("/authentication") ->
'operationId' => authenticators, 'operationId' => authenticators,
get => #{ get => #{
tags => ?API_TAGS_GLOBAL, tags => ?API_TAGS_GLOBAL,
description => <<"List authenticators for global authentication">>, description => ?DESC(authentication_get),
responses => #{ responses => #{
200 => emqx_dashboard_swagger:schema_with_example( 200 => emqx_dashboard_swagger:schema_with_example(
hoconsc:array(emqx_authn_schema:authenticator_type()), hoconsc:array(emqx_authn_schema:authenticator_type()),
@ -164,7 +164,7 @@ schema("/authentication") ->
}, },
post => #{ post => #{
tags => ?API_TAGS_GLOBAL, tags => ?API_TAGS_GLOBAL,
description => <<"Create authenticator for global authentication">>, description => ?DESC(authentication_post),
'requestBody' => emqx_dashboard_swagger:schema_with_examples( 'requestBody' => emqx_dashboard_swagger:schema_with_examples(
emqx_authn_schema:authenticator_type(), emqx_authn_schema:authenticator_type(),
authenticator_examples() authenticator_examples()
@ -184,7 +184,7 @@ schema("/authentication/:id") ->
'operationId' => authenticator, 'operationId' => authenticator,
get => #{ get => #{
tags => ?API_TAGS_GLOBAL, tags => ?API_TAGS_GLOBAL,
description => <<"Get authenticator from global authentication chain">>, description => ?DESC(authentication_id_get),
parameters => [param_auth_id()], parameters => [param_auth_id()],
responses => #{ responses => #{
200 => emqx_dashboard_swagger:schema_with_examples( 200 => emqx_dashboard_swagger:schema_with_examples(
@ -196,7 +196,7 @@ schema("/authentication/:id") ->
}, },
put => #{ put => #{
tags => ?API_TAGS_GLOBAL, tags => ?API_TAGS_GLOBAL,
description => <<"Update authenticator from global authentication chain">>, description => ?DESC(authentication_id_put),
parameters => [param_auth_id()], parameters => [param_auth_id()],
'requestBody' => emqx_dashboard_swagger:schema_with_examples( 'requestBody' => emqx_dashboard_swagger:schema_with_examples(
emqx_authn_schema:authenticator_type(), emqx_authn_schema:authenticator_type(),
@ -214,7 +214,7 @@ schema("/authentication/:id") ->
}, },
delete => #{ delete => #{
tags => ?API_TAGS_GLOBAL, tags => ?API_TAGS_GLOBAL,
description => <<"Delete authenticator from global authentication chain">>, description => ?DESC(authentication_id_delete),
parameters => [param_auth_id()], parameters => [param_auth_id()],
responses => #{ responses => #{
204 => <<"Authenticator deleted">>, 204 => <<"Authenticator deleted">>,
@ -227,7 +227,7 @@ schema("/authentication/:id/status") ->
'operationId' => authenticator_status, 'operationId' => authenticator_status,
get => #{ get => #{
tags => ?API_TAGS_GLOBAL, tags => ?API_TAGS_GLOBAL,
description => <<"Get authenticator status from global authentication chain">>, description => ?DESC(authentication_id_status_get),
parameters => [param_auth_id()], parameters => [param_auth_id()],
responses => #{ responses => #{
200 => emqx_dashboard_swagger:schema_with_examples( 200 => emqx_dashboard_swagger:schema_with_examples(
@ -243,7 +243,7 @@ schema("/listeners/:listener_id/authentication") ->
'operationId' => listener_authenticators, 'operationId' => listener_authenticators,
get => #{ get => #{
tags => ?API_TAGS_SINGLE, tags => ?API_TAGS_SINGLE,
description => <<"List authenticators for listener authentication">>, description => ?DESC(listeners_listener_id_authentication_get),
parameters => [param_listener_id()], parameters => [param_listener_id()],
responses => #{ responses => #{
200 => emqx_dashboard_swagger:schema_with_example( 200 => emqx_dashboard_swagger:schema_with_example(
@ -254,7 +254,7 @@ schema("/listeners/:listener_id/authentication") ->
}, },
post => #{ post => #{
tags => ?API_TAGS_SINGLE, tags => ?API_TAGS_SINGLE,
description => <<"Create authenticator for listener authentication">>, description => ?DESC(listeners_listener_id_authentication_post),
parameters => [param_listener_id()], parameters => [param_listener_id()],
'requestBody' => emqx_dashboard_swagger:schema_with_examples( 'requestBody' => emqx_dashboard_swagger:schema_with_examples(
emqx_authn_schema:authenticator_type(), emqx_authn_schema:authenticator_type(),
@ -275,7 +275,7 @@ schema("/listeners/:listener_id/authentication/:id") ->
'operationId' => listener_authenticator, 'operationId' => listener_authenticator,
get => #{ get => #{
tags => ?API_TAGS_SINGLE, tags => ?API_TAGS_SINGLE,
description => <<"Get authenticator from listener authentication chain">>, description => ?DESC(listeners_listener_id_authentication_id_get),
parameters => [param_listener_id(), param_auth_id()], parameters => [param_listener_id(), param_auth_id()],
responses => #{ responses => #{
200 => emqx_dashboard_swagger:schema_with_examples( 200 => emqx_dashboard_swagger:schema_with_examples(
@ -287,7 +287,7 @@ schema("/listeners/:listener_id/authentication/:id") ->
}, },
put => #{ put => #{
tags => ?API_TAGS_SINGLE, tags => ?API_TAGS_SINGLE,
description => <<"Update authenticator from listener authentication chain">>, description => ?DESC(listeners_listener_id_authentication_id_put),
parameters => [param_listener_id(), param_auth_id()], parameters => [param_listener_id(), param_auth_id()],
'requestBody' => emqx_dashboard_swagger:schema_with_examples( 'requestBody' => emqx_dashboard_swagger:schema_with_examples(
emqx_authn_schema:authenticator_type(), emqx_authn_schema:authenticator_type(),
@ -305,7 +305,7 @@ schema("/listeners/:listener_id/authentication/:id") ->
}, },
delete => #{ delete => #{
tags => ?API_TAGS_SINGLE, tags => ?API_TAGS_SINGLE,
description => <<"Delete authenticator from listener authentication chain">>, description => ?DESC(listeners_listener_id_authentication_id_delete),
parameters => [param_listener_id(), param_auth_id()], parameters => [param_listener_id(), param_auth_id()],
responses => #{ responses => #{
204 => <<"Authenticator deleted">>, 204 => <<"Authenticator deleted">>,
@ -318,7 +318,7 @@ schema("/listeners/:listener_id/authentication/:id/status") ->
'operationId' => listener_authenticator_status, 'operationId' => listener_authenticator_status,
get => #{ get => #{
tags => ?API_TAGS_SINGLE, tags => ?API_TAGS_SINGLE,
description => <<"Get authenticator status from listener authentication chain">>, description => ?DESC(listeners_listener_id_authentication_id_status_get),
parameters => [param_listener_id(), param_auth_id()], parameters => [param_listener_id(), param_auth_id()],
responses => #{ responses => #{
200 => emqx_dashboard_swagger:schema_with_examples( 200 => emqx_dashboard_swagger:schema_with_examples(
@ -334,7 +334,7 @@ schema("/authentication/:id/move") ->
'operationId' => authenticator_move, 'operationId' => authenticator_move,
post => #{ post => #{
tags => ?API_TAGS_GLOBAL, tags => ?API_TAGS_GLOBAL,
description => <<"Move authenticator in global authentication chain">>, description => ?DESC(authentication_id_move_post),
parameters => [param_auth_id()], parameters => [param_auth_id()],
'requestBody' => emqx_dashboard_swagger:schema_with_examples( 'requestBody' => emqx_dashboard_swagger:schema_with_examples(
ref(request_move), ref(request_move),
@ -352,7 +352,7 @@ schema("/listeners/:listener_id/authentication/:id/move") ->
'operationId' => listener_authenticator_move, 'operationId' => listener_authenticator_move,
post => #{ post => #{
tags => ?API_TAGS_SINGLE, tags => ?API_TAGS_SINGLE,
description => <<"Move authenticator in listener authentication chain">>, description => ?DESC(listeners_listener_id_authentication_id_move_post),
parameters => [param_listener_id(), param_auth_id()], parameters => [param_listener_id(), param_auth_id()],
'requestBody' => emqx_dashboard_swagger:schema_with_examples( 'requestBody' => emqx_dashboard_swagger:schema_with_examples(
ref(request_move), ref(request_move),
@ -370,7 +370,7 @@ schema("/authentication/:id/import_users") ->
'operationId' => authenticator_import_users, 'operationId' => authenticator_import_users,
post => #{ post => #{
tags => ?API_TAGS_GLOBAL, tags => ?API_TAGS_GLOBAL,
description => <<"Import users into authenticator in global authentication chain">>, description => ?DESC(authentication_id_import_users_post),
parameters => [param_auth_id()], parameters => [param_auth_id()],
'requestBody' => emqx_dashboard_swagger:schema_with_examples( 'requestBody' => emqx_dashboard_swagger:schema_with_examples(
ref(request_import_users), ref(request_import_users),
@ -388,7 +388,7 @@ schema("/listeners/:listener_id/authentication/:id/import_users") ->
'operationId' => listener_authenticator_import_users, 'operationId' => listener_authenticator_import_users,
post => #{ post => #{
tags => ?API_TAGS_SINGLE, tags => ?API_TAGS_SINGLE,
description => <<"Import users into authenticator in listener authentication chain">>, description => ?DESC(listeners_listener_id_authentication_id_import_users_post),
parameters => [param_listener_id(), param_auth_id()], parameters => [param_listener_id(), param_auth_id()],
'requestBody' => emqx_dashboard_swagger:schema_with_examples( 'requestBody' => emqx_dashboard_swagger:schema_with_examples(
ref(request_import_users), ref(request_import_users),
@ -406,7 +406,7 @@ schema("/authentication/:id/users") ->
'operationId' => authenticator_users, 'operationId' => authenticator_users,
post => #{ post => #{
tags => ?API_TAGS_GLOBAL, tags => ?API_TAGS_GLOBAL,
description => <<"Create users for authenticator in global authentication chain">>, description => ?DESC(authentication_id_users_post),
parameters => [param_auth_id()], parameters => [param_auth_id()],
'requestBody' => emqx_dashboard_swagger:schema_with_examples( 'requestBody' => emqx_dashboard_swagger:schema_with_examples(
ref(request_user_create), ref(request_user_create),
@ -423,7 +423,7 @@ schema("/authentication/:id/users") ->
}, },
get => #{ get => #{
tags => ?API_TAGS_GLOBAL, tags => ?API_TAGS_GLOBAL,
description => <<"List users in authenticator in global authentication chain">>, description => ?DESC(authentication_id_users_get),
parameters => [ parameters => [
param_auth_id(), param_auth_id(),
ref(emqx_dashboard_swagger, page), ref(emqx_dashboard_swagger, page),
@ -431,13 +431,13 @@ schema("/authentication/:id/users") ->
{like_username, {like_username,
mk(binary(), #{ mk(binary(), #{
in => query, in => query,
desc => <<"Fuzzy search username">>, desc => ?DESC(like_username),
required => false required => false
})}, })},
{like_clientid, {like_clientid,
mk(binary(), #{ mk(binary(), #{
in => query, in => query,
desc => <<"Fuzzy search clientid">>, desc => ?DESC(like_clientid),
required => false required => false
})} })}
], ],
@ -455,7 +455,7 @@ schema("/listeners/:listener_id/authentication/:id/users") ->
'operationId' => listener_authenticator_users, 'operationId' => listener_authenticator_users,
post => #{ post => #{
tags => ?API_TAGS_SINGLE, tags => ?API_TAGS_SINGLE,
description => <<"Create users for authenticator in global authentication chain">>, description => ?DESC(listeners_listener_id_authentication_id_users_post),
parameters => [param_auth_id(), param_listener_id()], parameters => [param_auth_id(), param_listener_id()],
'requestBody' => emqx_dashboard_swagger:schema_with_examples( 'requestBody' => emqx_dashboard_swagger:schema_with_examples(
ref(request_user_create), ref(request_user_create),
@ -472,7 +472,7 @@ schema("/listeners/:listener_id/authentication/:id/users") ->
}, },
get => #{ get => #{
tags => ?API_TAGS_SINGLE, tags => ?API_TAGS_SINGLE,
description => <<"List users in authenticator in listener authentication chain">>, description => ?DESC(listeners_listener_id_authentication_id_users_get),
parameters => [ parameters => [
param_listener_id(), param_listener_id(),
param_auth_id(), param_auth_id(),
@ -493,7 +493,7 @@ schema("/authentication/:id/users/:user_id") ->
'operationId' => authenticator_user, 'operationId' => authenticator_user,
get => #{ get => #{
tags => ?API_TAGS_GLOBAL, tags => ?API_TAGS_GLOBAL,
description => <<"Get user from authenticator in global authentication chain">>, description => ?DESC(authentication_id_users_user_id_get),
parameters => [param_auth_id(), param_user_id()], parameters => [param_auth_id(), param_user_id()],
responses => #{ responses => #{
200 => emqx_dashboard_swagger:schema_with_examples( 200 => emqx_dashboard_swagger:schema_with_examples(
@ -505,7 +505,7 @@ schema("/authentication/:id/users/:user_id") ->
}, },
put => #{ put => #{
tags => ?API_TAGS_GLOBAL, tags => ?API_TAGS_GLOBAL,
description => <<"Update user in authenticator in global authentication chain">>, description => ?DESC(authentication_id_users_user_id_put),
parameters => [param_auth_id(), param_user_id()], parameters => [param_auth_id(), param_user_id()],
'requestBody' => emqx_dashboard_swagger:schema_with_examples( 'requestBody' => emqx_dashboard_swagger:schema_with_examples(
ref(request_user_update), ref(request_user_update),
@ -522,7 +522,7 @@ schema("/authentication/:id/users/:user_id") ->
}, },
delete => #{ delete => #{
tags => ?API_TAGS_GLOBAL, tags => ?API_TAGS_GLOBAL,
description => <<"Update user in authenticator in global authentication chain">>, description => ?DESC(authentication_id_users_user_id_delete),
parameters => [param_auth_id(), param_user_id()], parameters => [param_auth_id(), param_user_id()],
responses => #{ responses => #{
204 => <<"User deleted">>, 204 => <<"User deleted">>,
@ -535,7 +535,7 @@ schema("/listeners/:listener_id/authentication/:id/users/:user_id") ->
'operationId' => listener_authenticator_user, 'operationId' => listener_authenticator_user,
get => #{ get => #{
tags => ?API_TAGS_SINGLE, tags => ?API_TAGS_SINGLE,
description => <<"Get user from authenticator in listener authentication chain">>, description => ?DESC(listeners_listener_id_authentication_id_users_user_id_get),
parameters => [param_listener_id(), param_auth_id(), param_user_id()], parameters => [param_listener_id(), param_auth_id(), param_user_id()],
responses => #{ responses => #{
200 => emqx_dashboard_swagger:schema_with_example( 200 => emqx_dashboard_swagger:schema_with_example(
@ -547,7 +547,7 @@ schema("/listeners/:listener_id/authentication/:id/users/:user_id") ->
}, },
put => #{ put => #{
tags => ?API_TAGS_SINGLE, tags => ?API_TAGS_SINGLE,
description => <<"Update user in authenticator in listener authentication chain">>, description => ?DESC(listeners_listener_id_authentication_id_users_user_id_put),
parameters => [param_listener_id(), param_auth_id(), param_user_id()], parameters => [param_listener_id(), param_auth_id(), param_user_id()],
'requestBody' => emqx_dashboard_swagger:schema_with_example( 'requestBody' => emqx_dashboard_swagger:schema_with_example(
ref(request_user_update), ref(request_user_update),
@ -564,7 +564,7 @@ schema("/listeners/:listener_id/authentication/:id/users/:user_id") ->
}, },
delete => #{ delete => #{
tags => ?API_TAGS_SINGLE, tags => ?API_TAGS_SINGLE,
description => <<"Update user in authenticator in listener authentication chain">>, description => ?DESC(listeners_listener_id_authentication_id_users_user_id_delete),
parameters => [param_listener_id(), param_auth_id(), param_user_id()], parameters => [param_listener_id(), param_auth_id(), param_user_id()],
responses => #{ responses => #{
204 => <<"User deleted">>, 204 => <<"User deleted">>,
@ -578,7 +578,7 @@ param_auth_id() ->
id, id,
mk(binary(), #{ mk(binary(), #{
in => path, in => path,
desc => <<"Authenticator ID">>, desc => ?DESC(param_auth_id),
required => true required => true
}) })
}. }.
@ -588,7 +588,7 @@ param_listener_id() ->
listener_id, listener_id,
mk(binary(), #{ mk(binary(), #{
in => path, in => path,
desc => <<"Listener ID">>, desc => ?DESC(param_listener_id),
required => true, required => true,
example => emqx_listeners:id_example() example => emqx_listeners:id_example()
}) })
@ -599,7 +599,7 @@ param_user_id() ->
user_id, user_id,
mk(binary(), #{ mk(binary(), #{
in => path, in => path,
desc => <<"User ID">> desc => ?DESC(param_user_id)
}) })
}. }.

View File

@ -17,7 +17,7 @@
-module(emqx_authn_schema). -module(emqx_authn_schema).
-elvis([{elvis_style, invalid_dynamic_call, disable}]). -elvis([{elvis_style, invalid_dynamic_call, disable}]).
-include_lib("typerefl/include/types.hrl"). -include_lib("hocon/include/hoconsc.hrl").
-import(hoconsc, [mk/2, ref/2]). -import(hoconsc, [mk/2, ref/2]).
-export([ -export([
@ -38,7 +38,7 @@ common_fields() ->
enable(type) -> boolean(); enable(type) -> boolean();
enable(default) -> true; enable(default) -> true;
enable(desc) -> "Set to <code>false</code> to disable this auth provider"; enable(desc) -> ?DESC(?FUNCTION_NAME);
enable(_) -> undefined. enable(_) -> undefined.
authenticator_type() -> authenticator_type() ->
@ -74,7 +74,7 @@ mechanism(Name) ->
hoconsc:enum([Name]), hoconsc:enum([Name]),
#{ #{
required => true, required => true,
desc => "Authentication mechanism." desc => ?DESC("mechanism")
} }
). ).
@ -83,51 +83,47 @@ backend(Name) ->
hoconsc:enum([Name]), hoconsc:enum([Name]),
#{ #{
required => true, required => true,
desc => "Backend type." desc => ?DESC("backend")
} }
). ).
fields("metrics_status_fields") -> fields("metrics_status_fields") ->
[ [
{"metrics", mk(ref(?MODULE, "metrics"), #{desc => "The metrics of the resource"})}, {"metrics", mk(ref(?MODULE, "metrics"), #{desc => ?DESC("metrics")})},
{"node_metrics", {"node_metrics",
mk( mk(
hoconsc:array(ref(?MODULE, "node_metrics")), hoconsc:array(ref(?MODULE, "node_metrics")),
#{desc => "The metrics of the resource for each node"} #{desc => ?DESC("node_metrics")}
)}, )},
{"status", mk(status(), #{desc => "The status of the resource"})}, {"status", mk(status(), #{desc => ?DESC("status")})},
{"node_status", {"node_status",
mk( mk(
hoconsc:array(ref(?MODULE, "node_status")), hoconsc:array(ref(?MODULE, "node_status")),
#{desc => "The status of the resource for each node"} #{desc => ?DESC("node_status")}
)} )}
]; ];
fields("metrics") -> fields("metrics") ->
[ [
{"matched", mk(integer(), #{desc => "Count of this resource is queried"})}, {"matched", mk(integer(), #{desc => ?DESC("matched")})},
{"success", mk(integer(), #{desc => "Count of query success"})}, {"success", mk(integer(), #{desc => ?DESC("success")})},
{"failed", mk(integer(), #{desc => "Count of query failed"})}, {"failed", mk(integer(), #{desc => ?DESC("failed")})},
{"rate", mk(float(), #{desc => "The rate of matched, times/second"})}, {"rate", mk(float(), #{desc => ?DESC("rate")})},
{"rate_max", mk(float(), #{desc => "The max rate of matched, times/second"})}, {"rate_max", mk(float(), #{desc => ?DESC("rate_max")})},
{"rate_last5m", {"rate_last5m", mk(float(), #{desc => ?DESC("rate_last5m")})}
mk(
float(),
#{desc => "The average rate of matched in the last 5 minutes, times/second"}
)}
]; ];
fields("node_metrics") -> fields("node_metrics") ->
[ [
node_name(), node_name(),
{"metrics", mk(ref(?MODULE, "metrics"), #{})} {"metrics", mk(ref(?MODULE, "metrics"), #{desc => ?DESC("metrics")})}
]; ];
fields("node_status") -> fields("node_status") ->
[ [
node_name(), node_name(),
{"status", mk(status(), #{desc => "Status of the node."})} {"status", mk(status(), #{desc => ?DESC("node_status")})}
]. ].
status() -> status() ->
hoconsc:enum([connected, disconnected, connecting]). hoconsc:enum([connected, disconnected, connecting]).
node_name() -> node_name() ->
{"node", mk(binary(), #{desc => "The node name", example => "emqx@127.0.0.1"})}. {"node", mk(binary(), #{desc => ?DESC("node"), example => "emqx@127.0.0.1"})}.

View File

@ -18,7 +18,7 @@
-include("emqx_authn.hrl"). -include("emqx_authn.hrl").
-include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/logger.hrl").
-include_lib("typerefl/include/types.hrl"). -include_lib("hocon/include/hoconsc.hrl").
-include_lib("emqx_connector/include/emqx_connector.hrl"). -include_lib("emqx_connector/include/emqx_connector.hrl").
-behaviour(hocon_schema). -behaviour(hocon_schema).
@ -62,19 +62,19 @@ roots() ->
fields(get) -> fields(get) ->
[ [
{method, #{type => get, required => true, default => post, desc => "HTTP method."}}, {method, #{type => get, required => true, default => post, desc => ?DESC(method)}},
{headers, fun headers_no_content_type/1} {headers, fun headers_no_content_type/1}
] ++ common_fields(); ] ++ common_fields();
fields(post) -> fields(post) ->
[ [
{method, #{type => post, required => true, default => post, desc => "HTTP method."}}, {method, #{type => post, required => true, default => post, desc => ?DESC(method)}},
{headers, fun headers/1} {headers, fun headers/1}
] ++ common_fields(). ] ++ common_fields().
desc(get) -> desc(get) ->
"Settings for HTTP-based authentication (GET)."; ?DESC(get);
desc(post) -> desc(post) ->
"Settings for HTTP-based authentication (POST)."; ?DESC(post);
desc(_) -> desc(_) ->
undefined. undefined.
@ -83,8 +83,7 @@ common_fields() ->
{mechanism, emqx_authn_schema:mechanism(password_based)}, {mechanism, emqx_authn_schema:mechanism(password_based)},
{backend, emqx_authn_schema:backend(http)}, {backend, emqx_authn_schema:backend(http)},
{url, fun url/1}, {url, fun url/1},
{body, {body, hoconsc:mk(map([{fuzzy, term(), binary()}]), #{desc => ?DESC(body)})},
hoconsc:mk(map([{fuzzy, term(), binary()}]), #{desc => "Body of the HTTP request."})},
{request_timeout, fun request_timeout/1} {request_timeout, fun request_timeout/1}
] ++ emqx_authn_schema:common_fields() ++ ] ++ emqx_authn_schema:common_fields() ++
maps:to_list( maps:to_list(
@ -104,7 +103,7 @@ validations() ->
]. ].
url(type) -> binary(); url(type) -> binary();
url(desc) -> "URL of the auth server."; url(desc) -> ?DESC(?FUNCTION_NAME);
url(validator) -> [?NOT_EMPTY("the value of the field 'url' cannot be empty")]; url(validator) -> [?NOT_EMPTY("the value of the field 'url' cannot be empty")];
url(required) -> true; url(required) -> true;
url(_) -> undefined. url(_) -> undefined.
@ -112,7 +111,7 @@ url(_) -> undefined.
headers(type) -> headers(type) ->
map(); map();
headers(desc) -> headers(desc) ->
"List of HTTP headers."; ?DESC(?FUNCTION_NAME);
headers(converter) -> headers(converter) ->
fun(Headers) -> fun(Headers) ->
maps:merge(default_headers(), transform_header_name(Headers)) maps:merge(default_headers(), transform_header_name(Headers))
@ -125,7 +124,7 @@ headers(_) ->
headers_no_content_type(type) -> headers_no_content_type(type) ->
map(); map();
headers_no_content_type(desc) -> headers_no_content_type(desc) ->
"List of HTTP headers."; ?DESC(?FUNCTION_NAME);
headers_no_content_type(converter) -> headers_no_content_type(converter) ->
fun(Headers) -> fun(Headers) ->
maps:merge(default_headers_no_content_type(), transform_header_name(Headers)) maps:merge(default_headers_no_content_type(), transform_header_name(Headers))
@ -136,7 +135,7 @@ headers_no_content_type(_) ->
undefined. undefined.
request_timeout(type) -> emqx_schema:duration_ms(); request_timeout(type) -> emqx_schema:duration_ms();
request_timeout(desc) -> "HTTP request timeout"; request_timeout(desc) -> ?DESC(?FUNCTION_NAME);
request_timeout(default) -> <<"5s">>; request_timeout(default) -> <<"5s">>;
request_timeout(_) -> undefined. request_timeout(_) -> undefined.

View File

@ -17,8 +17,8 @@
-module(emqx_authn_jwt). -module(emqx_authn_jwt).
-include("emqx_authn.hrl"). -include("emqx_authn.hrl").
-include_lib("typerefl/include/types.hrl").
-include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/logger.hrl").
-include_lib("hocon/include/hoconsc.hrl").
-behaviour(hocon_schema). -behaviour(hocon_schema).
-behaviour(emqx_authentication). -behaviour(emqx_authentication).
@ -55,22 +55,22 @@ roots() ->
fields('hmac-based') -> fields('hmac-based') ->
[ [
{use_jwks, sc(hoconsc:enum([false]), #{required => true, desc => ""})}, {use_jwks, sc(hoconsc:enum([false]), #{required => true, desc => ?DESC(use_jwks)})},
{algorithm, {algorithm,
sc(hoconsc:enum(['hmac-based']), #{required => true, desc => "Signing algorithm."})}, sc(hoconsc:enum(['hmac-based']), #{required => true, desc => ?DESC(algorithm)})},
{secret, fun secret/1}, {secret, fun secret/1},
{secret_base64_encoded, fun secret_base64_encoded/1} {secret_base64_encoded, fun secret_base64_encoded/1}
] ++ common_fields(); ] ++ common_fields();
fields('public-key') -> fields('public-key') ->
[ [
{use_jwks, sc(hoconsc:enum([false]), #{required => true, desc => ""})}, {use_jwks, sc(hoconsc:enum([false]), #{required => true, desc => ?DESC(use_jwks)})},
{algorithm, {algorithm,
sc(hoconsc:enum(['public-key']), #{required => true, desc => "Signing algorithm."})}, sc(hoconsc:enum(['public-key']), #{required => true, desc => ?DESC(algorithm)})},
{certificate, fun certificate/1} {certificate, fun certificate/1}
] ++ common_fields(); ] ++ common_fields();
fields('jwks') -> fields('jwks') ->
[ [
{use_jwks, sc(hoconsc:enum([true]), #{required => true, desc => ""})}, {use_jwks, sc(hoconsc:enum([true]), #{required => true, desc => ?DESC(use_jwks)})},
{endpoint, fun endpoint/1}, {endpoint, fun endpoint/1},
{pool_size, fun pool_size/1}, {pool_size, fun pool_size/1},
{refresh_interval, fun refresh_interval/1}, {refresh_interval, fun refresh_interval/1},
@ -79,14 +79,14 @@ fields('jwks') ->
hoconsc:ref(?MODULE, ssl_enable), hoconsc:ref(?MODULE, ssl_enable),
hoconsc:ref(?MODULE, ssl_disable) hoconsc:ref(?MODULE, ssl_disable)
]), ]),
desc => "Enable/disable SSL.", desc => ?DESC(ssl),
default => #{<<"enable">> => false}, default => #{<<"enable">> => false},
required => false required => false
}} }}
] ++ common_fields(); ] ++ common_fields();
fields(ssl_enable) -> fields(ssl_enable) ->
[ [
{enable, #{type => true, desc => ""}}, {enable, #{type => true, desc => ?DESC(enable)}},
{cacertfile, fun cacertfile/1}, {cacertfile, fun cacertfile/1},
{certfile, fun certfile/1}, {certfile, fun certfile/1},
{keyfile, fun keyfile/1}, {keyfile, fun keyfile/1},
@ -94,18 +94,18 @@ fields(ssl_enable) ->
{server_name_indication, fun server_name_indication/1} {server_name_indication, fun server_name_indication/1}
]; ];
fields(ssl_disable) -> fields(ssl_disable) ->
[{enable, #{type => false, desc => ""}}]. [{enable, #{type => false, desc => ?DESC(enable)}}].
desc('hmac-based') -> desc('hmac-based') ->
"Settings for HMAC-based token signing algorithm."; ?DESC('hmac-based');
desc('public-key') -> desc('public-key') ->
"Settings for public key-based token signing algorithm."; ?DESC('public-key');
desc('jwks') -> desc('jwks') ->
"Settings for a signing using JSON Web Key Set (JWKs)."; ?DESC('jwks');
desc(ssl_disable) -> desc(ssl_disable) ->
""; ?DESC(ssl_disable);
desc(ssl_enable) -> desc(ssl_enable) ->
"SSL configuration."; ?DESC(ssl_enable);
desc(_) -> desc(_) ->
undefined. undefined.
@ -116,56 +116,56 @@ common_fields() ->
] ++ emqx_authn_schema:common_fields(). ] ++ emqx_authn_schema:common_fields().
secret(type) -> binary(); secret(type) -> binary();
secret(desc) -> "The key to verify the JWT Token using HMAC algorithm."; secret(desc) -> ?DESC(?FUNCTION_NAME);
secret(required) -> true; secret(required) -> true;
secret(_) -> undefined. secret(_) -> undefined.
secret_base64_encoded(type) -> boolean(); secret_base64_encoded(type) -> boolean();
secret_base64_encoded(desc) -> "Enable/disable base64 encoding of the secret."; secret_base64_encoded(desc) -> ?DESC(?FUNCTION_NAME);
secret_base64_encoded(default) -> false; secret_base64_encoded(default) -> false;
secret_base64_encoded(_) -> undefined. secret_base64_encoded(_) -> undefined.
certificate(type) -> string(); certificate(type) -> string();
certificate(desc) -> "The certificate used for signing the token."; certificate(desc) -> ?DESC(?FUNCTION_NAME);
certificate(required) -> ture; certificate(required) -> ture;
certificate(_) -> undefined. certificate(_) -> undefined.
endpoint(type) -> string(); endpoint(type) -> string();
endpoint(desc) -> "JWKs endpoint."; endpoint(desc) -> ?DESC(?FUNCTION_NAME);
endpoint(required) -> true; endpoint(required) -> true;
endpoint(_) -> undefined. endpoint(_) -> undefined.
refresh_interval(type) -> integer(); refresh_interval(type) -> integer();
refresh_interval(desc) -> "JWKs refresh interval"; refresh_interval(desc) -> ?DESC(?FUNCTION_NAME);
refresh_interval(default) -> 300; refresh_interval(default) -> 300;
refresh_interval(validator) -> [fun(I) -> I > 0 end]; refresh_interval(validator) -> [fun(I) -> I > 0 end];
refresh_interval(_) -> undefined. refresh_interval(_) -> undefined.
cacertfile(type) -> string(); cacertfile(type) -> string();
cacertfile(desc) -> "Path to the SSL CA certificate file."; cacertfile(desc) -> ?DESC(?FUNCTION_NAME);
cacertfile(_) -> undefined. cacertfile(_) -> undefined.
certfile(type) -> string(); certfile(type) -> string();
certfile(desc) -> "Path to the SSL certificate file."; certfile(desc) -> ?DESC(?FUNCTION_NAME);
certfile(_) -> undefined. certfile(_) -> undefined.
keyfile(type) -> string(); keyfile(type) -> string();
keyfile(desc) -> "Path to the SSL secret key file."; keyfile(desc) -> ?DESC(?FUNCTION_NAME);
keyfile(_) -> undefined. keyfile(_) -> undefined.
verify(type) -> hoconsc:enum([verify_peer, verify_none]); verify(type) -> hoconsc:enum([verify_peer, verify_none]);
verify(desc) -> "Enable or disable SSL peer verification."; verify(desc) -> ?DESC(?FUNCTION_NAME);
verify(default) -> verify_none; verify(default) -> verify_none;
verify(_) -> undefined. verify(_) -> undefined.
server_name_indication(type) -> string(); server_name_indication(type) -> string();
server_name_indication(desc) -> "SSL SNI (Server Name Indication)"; server_name_indication(desc) -> ?DESC(?FUNCTION_NAME);
server_name_indication(_) -> undefined. server_name_indication(_) -> undefined.
verify_claims(type) -> verify_claims(type) ->
list(); list();
verify_claims(desc) -> verify_claims(desc) ->
"The list of claims to verify."; ?DESC(?FUNCTION_NAME);
verify_claims(default) -> verify_claims(default) ->
#{}; #{};
verify_claims(validator) -> verify_claims(validator) ->
@ -180,7 +180,7 @@ verify_claims(_) ->
undefined. undefined.
pool_size(type) -> integer(); pool_size(type) -> integer();
pool_size(desc) -> "JWKS connection count"; pool_size(desc) -> ?DESC(?FUNCTION_NAME);
pool_size(default) -> 8; pool_size(default) -> 8;
pool_size(validator) -> [fun(I) -> I > 0 end]; pool_size(validator) -> [fun(I) -> I > 0 end];
pool_size(_) -> undefined. pool_size(_) -> undefined.

View File

@ -18,7 +18,7 @@
-include("emqx_authn.hrl"). -include("emqx_authn.hrl").
-include_lib("stdlib/include/ms_transform.hrl"). -include_lib("stdlib/include/ms_transform.hrl").
-include_lib("typerefl/include/types.hrl"). -include_lib("hocon/include/hoconsc.hrl").
-behaviour(hocon_schema). -behaviour(hocon_schema).
-behaviour(emqx_authentication). -behaviour(emqx_authentication).
@ -110,12 +110,12 @@ fields(?CONF_NS) ->
] ++ emqx_authn_schema:common_fields(). ] ++ emqx_authn_schema:common_fields().
desc(?CONF_NS) -> desc(?CONF_NS) ->
"Configuration for authentication using the built-in database."; ?DESC(?CONF_NS);
desc(_) -> desc(_) ->
undefined. undefined.
user_id_type(type) -> user_id_type(); user_id_type(type) -> user_id_type();
user_id_type(desc) -> "Authenticate by client ID or username."; user_id_type(desc) -> ?DESC(?FUNCTION_NAME);
user_id_type(default) -> <<"username">>; user_id_type(default) -> <<"username">>;
user_id_type(required) -> true; user_id_type(required) -> true;
user_id_type(_) -> undefined. user_id_type(_) -> undefined.

View File

@ -18,7 +18,7 @@
-include("emqx_authn.hrl"). -include("emqx_authn.hrl").
-include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/logger.hrl").
-include_lib("typerefl/include/types.hrl"). -include_lib("hocon/include/hoconsc.hrl").
-behaviour(hocon_schema). -behaviour(hocon_schema).
-behaviour(emqx_authentication). -behaviour(emqx_authentication).
@ -61,17 +61,17 @@ fields('sharded-cluster') ->
common_fields() ++ emqx_connector_mongo:fields(sharded). common_fields() ++ emqx_connector_mongo:fields(sharded).
desc(standalone) -> desc(standalone) ->
"Configuration for a standalone MongoDB instance."; ?DESC(standalone);
desc('replica-set') -> desc('replica-set') ->
"Configuration for a replica set."; ?DESC('replica-set');
desc('sharded-cluster') -> desc('sharded-cluster') ->
"Configuration for a sharded cluster."; ?DESC('sharded-cluster');
desc(_) -> desc(_) ->
undefined. undefined.
common_fields() -> common_fields() ->
[ [
{mechanism, emqx_authn_schema:mechanism('password_based')}, {mechanism, emqx_authn_schema:mechanism(password_based)},
{backend, emqx_authn_schema:backend(mongodb)}, {backend, emqx_authn_schema:backend(mongodb)},
{collection, fun collection/1}, {collection, fun collection/1},
{selector, fun selector/1}, {selector, fun selector/1},
@ -82,32 +82,29 @@ common_fields() ->
] ++ emqx_authn_schema:common_fields(). ] ++ emqx_authn_schema:common_fields().
collection(type) -> binary(); collection(type) -> binary();
collection(desc) -> "Collection used to store authentication data."; collection(desc) -> ?DESC(?FUNCTION_NAME);
collection(required) -> true; collection(required) -> true;
collection(_) -> undefined. collection(_) -> undefined.
selector(type) -> selector(type) ->
map(); map();
selector(desc) -> selector(desc) ->
"Statement that is executed during the authentication process. " ?DESC(?FUNCTION_NAME);
"Commands can support following wildcards:\n"
" - `${username}`: substituted with client's username\n"
" - `${clientid}`: substituted with the clientid";
selector(_) -> selector(_) ->
undefined. undefined.
password_hash_field(type) -> binary(); password_hash_field(type) -> binary();
password_hash_field(desc) -> "Document field that contains password hash."; password_hash_field(desc) -> ?DESC(?FUNCTION_NAME);
password_hash_field(required) -> false; password_hash_field(required) -> false;
password_hash_field(_) -> undefined. password_hash_field(_) -> undefined.
salt_field(type) -> binary(); salt_field(type) -> binary();
salt_field(desc) -> "Document field that contains the password salt."; salt_field(desc) -> ?DESC(?FUNCTION_NAME);
salt_field(required) -> false; salt_field(required) -> false;
salt_field(_) -> undefined. salt_field(_) -> undefined.
is_superuser_field(type) -> binary(); is_superuser_field(type) -> binary();
is_superuser_field(desc) -> "Document field that defines if the user has superuser privileges."; is_superuser_field(desc) -> ?DESC(?FUNCTION_NAME);
is_superuser_field(required) -> false; is_superuser_field(required) -> false;
is_superuser_field(_) -> undefined. is_superuser_field(_) -> undefined.

View File

@ -18,7 +18,7 @@
-include("emqx_authn.hrl"). -include("emqx_authn.hrl").
-include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/logger.hrl").
-include_lib("typerefl/include/types.hrl"). -include_lib("hocon/include/hoconsc.hrl").
-behaviour(hocon_schema). -behaviour(hocon_schema).
-behaviour(emqx_authentication). -behaviour(emqx_authentication).
@ -59,17 +59,17 @@ fields(?CONF_NS) ->
proplists:delete(prepare_statement, emqx_connector_mysql:fields(config)). proplists:delete(prepare_statement, emqx_connector_mysql:fields(config)).
desc(?CONF_NS) -> desc(?CONF_NS) ->
"Configuration for authentication using MySQL database."; ?DESC(?CONF_NS);
desc(_) -> desc(_) ->
undefined. undefined.
query(type) -> string(); query(type) -> string();
query(desc) -> "SQL query used to lookup client data."; query(desc) -> ?DESC(?FUNCTION_NAME);
query(required) -> true; query(required) -> true;
query(_) -> undefined. query(_) -> undefined.
query_timeout(type) -> emqx_schema:duration_ms(); query_timeout(type) -> emqx_schema:duration_ms();
query_timeout(desc) -> "Timeout for the SQL query."; query_timeout(desc) -> ?DESC(?FUNCTION_NAME);
query_timeout(default) -> "5s"; query_timeout(default) -> "5s";
query_timeout(_) -> undefined. query_timeout(_) -> undefined.

View File

@ -19,7 +19,7 @@
-include("emqx_authn.hrl"). -include("emqx_authn.hrl").
-include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/logger.hrl").
-include_lib("epgsql/include/epgsql.hrl"). -include_lib("epgsql/include/epgsql.hrl").
-include_lib("typerefl/include/types.hrl"). -include_lib("hocon/include/hoconsc.hrl").
-behaviour(hocon_schema). -behaviour(hocon_schema).
-behaviour(emqx_authentication). -behaviour(emqx_authentication).
@ -63,12 +63,12 @@ fields(?CONF_NS) ->
proplists:delete(prepare_statement, emqx_connector_pgsql:fields(config)). proplists:delete(prepare_statement, emqx_connector_pgsql:fields(config)).
desc(?CONF_NS) -> desc(?CONF_NS) ->
"Configuration for PostgreSQL authentication backend."; ?DESC(?CONF_NS);
desc(_) -> desc(_) ->
undefined. undefined.
query(type) -> string(); query(type) -> string();
query(desc) -> "`SQL` query for looking up authentication data."; query(desc) -> ?DESC(?FUNCTION_NAME);
query(required) -> true; query(required) -> true;
query(_) -> undefined. query(_) -> undefined.

View File

@ -18,7 +18,7 @@
-include("emqx_authn.hrl"). -include("emqx_authn.hrl").
-include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/logger.hrl").
-include_lib("typerefl/include/types.hrl"). -include_lib("hocon/include/hoconsc.hrl").
-behaviour(hocon_schema). -behaviour(hocon_schema).
-behaviour(emqx_authentication). -behaviour(emqx_authentication).
@ -61,24 +61,24 @@ fields(sentinel) ->
common_fields() ++ emqx_connector_redis:fields(sentinel). common_fields() ++ emqx_connector_redis:fields(sentinel).
desc(standalone) -> desc(standalone) ->
"Configuration for a standalone Redis instance."; ?DESC(standalone);
desc(cluster) -> desc(cluster) ->
"Configuration for a Redis cluster."; ?DESC(cluster);
desc(sentinel) -> desc(sentinel) ->
"Configuration for a Redis Sentinel."; ?DESC(sentinel);
desc(_) -> desc(_) ->
"". "".
common_fields() -> common_fields() ->
[ [
{mechanism, emqx_authn_schema:mechanism('password_based')}, {mechanism, emqx_authn_schema:mechanism(password_based)},
{backend, emqx_authn_schema:backend(redis)}, {backend, emqx_authn_schema:backend(redis)},
{cmd, fun cmd/1}, {cmd, fun cmd/1},
{password_hash_algorithm, fun emqx_authn_password_hashing:type_ro/1} {password_hash_algorithm, fun emqx_authn_password_hashing:type_ro/1}
] ++ emqx_authn_schema:common_fields(). ] ++ emqx_authn_schema:common_fields().
cmd(type) -> string(); cmd(type) -> string();
cmd(desc) -> "Redis query."; cmd(desc) -> ?DESC(?FUNCTION_NAME);
cmd(required) -> true; cmd(required) -> true;
cmd(_) -> undefined. cmd(_) -> undefined.

View File

@ -0,0 +1,6 @@
emqx_authz_api_cache {
authorization_cache_delete {
en: """Clean all authorization cache in the cluster."""
zh: """清除集群中所有鉴权数据缓存"""
}
}

View File

@ -0,0 +1,177 @@
emqx_authz_api_mnesia {
users_username_get {
desc {
en: """Show the list of record for username"""
zh: """获取内置数据库中所有用户名类型的规则记录"""
}
}
users_username_post {
desc {
en: """Add new records for username"""
zh: """添加内置数据库中用户名类型的规则记录"""
}
}
users_clientid_get {
desc {
en: """Show the list of record for clientid"""
zh: """获取内置数据库中所有客户端标识符类型的规则记录"""
}
}
users_clientid_post {
desc {
en: """Add new records for clientid"""
zh: """添加内置数据库中客户端标识符类型的规则记录"""
}
}
user_username_get {
desc {
en: """Get record info for username"""
zh: """获取内置数据库中指定用户名类型的规则记录"""
}
}
user_username_put {
desc {
en: """Set record for username"""
zh: """更新内置数据库中指定用户名类型的规则记录"""
}
}
user_username_delete {
desc {
en: """Delete one record for username"""
zh: """删除内置数据库中指定用户名类型的规则记录"""
}
}
user_clientid_get {
desc {
en: """Get record info for clientid"""
zh: """获取内置数据库中指定客户端标识符类型的规则记录"""
}
}
user_clientid_put {
desc {
en: """Set record for clientid"""
zh: """更新内置数据库中指定客户端标识符类型的规则记录"""
}
}
user_clientid_delete {
desc {
en: """Delete one record for clientid"""
zh: """删除内置数据库中指定客户端标识符类型的规则记录"""
}
}
rules_for_all_get {
desc {
en: """Show the list of rules for all"""
zh: """列出为所有客户端启用的规则列表"""
}
}
rules_for_all_post {
desc {
en: """
Create/Update the list of rules for all.
Set a empty list to clean up rules
"""
zh: """
创建/更新 为所有客户端启用的规则列表。
设为空列表以清楚所有规则
"""
}
}
purge_all_delete {
desc {
en: """Purge all records for username/clientid/all"""
zh: """清除所有内置数据库中的规则, 用户名/客户端标识符/所有"""
}
}
fuzzy_username {
desc {
en: """Fuzzy search `username` as substring"""
zh: """使用字串匹配模糊搜索用户名"""
}
label {
en: """fuzzy_username"""
zh: """用户名子串"""
}
}
fuzzy_clientid {
desc {
en: """Fuzzy search `clientid` as substring"""
zh: """使用字串匹配模糊搜索客户端标识符"""
}
label {
en: """fuzzy_clientid"""
zh: """客户端标识符子串"""
}
}
topic {
desc {
en: """Rule on specific topic"""
zh: """在指定主题上的规则"""
}
label {
en: """topic"""
zh: """主题"""
}
}
permission {
desc {
en: """Permission"""
zh: """权限"""
}
label {
en: """permission"""
zh: """权限"""
}
}
action {
desc {
en: """Authorized action (pub/sub/all)"""
zh: """被授权的行为 (发布/订阅/所有)"""
}
label {
en: """action"""
zh: """行为"""
}
}
clientid {
desc {
en: """ClientID"""
zh: """客户端标识符"""
}
label {
en: """clientid"""
zh: """客户端标识符"""
}
}
username {
desc {
en: """Username"""
zh: """用户名"""
}
label {
en: """username"""
zh: """用户名"""
}
}
}

View File

@ -0,0 +1,188 @@
emqx_authz_api_schema {
enable {
desc {
en: """Set to <code>true</code> or <code>false</code> to disable this ACL provider"""
zh: """设为 <code>true</code> 或 <code>false</code> 以启用或禁用此访问控制数据源"""
}
label {
en: """enable"""
zh: """enable"""
}
}
type {
desc {
en: """Backend type."""
zh: """数据后端类型"""
}
label {
en: """type"""
zh: """type"""
}
}
#==== authz_file
rules {
desc {
en: """Authorization static file rules."""
zh: """静态鉴权文件规则"""
}
label {
en: """rules"""
zh: """规则"""
}
}
#==== authz_http
method {
desc {
en: """HTTP method."""
zh: """HTTP 请求方法"""
}
label {
en: """method"""
zh: """method"""
}
}
url {
desc {
en: """URL of the auth server."""
zh: """认证服务器 URL"""
}
label {
en: """url"""
zh: """url"""
}
}
headers {
desc {
en: """List of HTTP headers."""
zh: """"""
}
label {
en: """headers"""
zh: """请求头"""
}
}
headers_no_content_type {
desc {
en: """List of HTTP headers (without `content_type`)."""
zh: """"""
}
label {
en: """headers_no_content_type"""
zh: """请求头(无 content-type)"""
}
}
body {
desc {
en: """HTTP request body."""
zh: """HTTP 请求体"""
}
label {
en: """body"""
zh: """请求体"""
}
}
request_timeout {
desc {
en: """Request timeout."""
zh: """请求超时时间"""
}
label {
en: """request_timeout"""
zh: """请求超时"""
}
}
#==== authz_mnesia
# only common fields(`enable` and `type`)
#==== authz_mongo
collection {
desc {
en: """`MongoDB` collection containing the authorization data."""
zh: """`MongoDB` 鉴权数据集"""
}
label {
en: """collection"""
zh: """数据集"""
}
}
selector {
desc {
en: """
Statement that is executed during the authorize process.
Commands can support following wildcards:\n
- `${username}`: substituted with client's username\n
- `${clientid}`: substituted with the clientid
"""
zh: """
鉴权过程中所使用的查询命令。
查询命令支持如下占位符:
- `${username}`: 代替客户端的用户名
- `${clientid}`: 代替客户端的客户端标识符"""
}
label {
en: """selector"""
zh: """selector"""
}
}
#==== authz_mysql
# `query`, is common field
#==== authz_pgsql
# `query`, is common field
#==== authz_redis
cmd {
desc {
en: """Database query used to retrieve authorization data."""
zh: """访问控制数据查询命令"""
}
label {
en: """cmd"""
zh: """查询命令"""
}
}
#==== common field for DBs (except mongodb and redis)
query {
desc {
en: """Database query used to retrieve authorization data."""
zh: """访问控制数据查询语句"""
}
label {
en: """query"""
zh: """查询语句"""
}
}
#==== fields
position {
desc {
en: """Where to place the source"""
zh: """认证数据源位置"""
}
label {
en: """position"""
zh: """位置"""
}
}
}

View File

@ -0,0 +1,11 @@
emqx_authz_api_settings {
authorization_settings_get {
en: """Get authorization settings"""
zh: """获取鉴权配置"""
}
authorization_settings_put {
en: """Update authorization settings"""
zh: """更新鉴权配置"""
}
}

View File

@ -0,0 +1,116 @@
emqx_authz_api_sources {
authorization_sources_get {
desc {
en: """List all authorization sources"""
zh: """列出所有鉴权数据源"""
}
}
authorization_sources_post {
desc {
en: """Add a new source"""
zh: """添加鉴权数据源"""
}
}
authorization_sources_type_get {
desc {
en: """Get a authorization source"""
zh: """获取指定类型的鉴权数据源"""
}
}
authorization_sources_type_put {
desc {
en: """Update source"""
zh: """更新指定类型的鉴权数据源"""
}
}
authorization_sources_type_delete {
desc {
en: """Delete source"""
zh: """删除指定类型的鉴权数据源"""
}
}
authorization_sources_type_status_get {
desc {
en: """Get a authorization source"""
zh: """获取指定鉴权数据源的状态"""
}
}
authorization_sources_type_move_post {
desc {
en: """Change the exection order of sources"""
zh: """更新鉴权数据源的优先执行顺序"""
}
}
sources {
desc {
en: """Authorization source"""
zh: """鉴权数据源列表"""
}
label {
en: """sources"""
zh: """数据源列表"""
}
}
sources {
desc {
en: """Authorization sources"""
zh: """鉴权数据源列表"""
}
label {
en: """sources"""
zh: """数据源列表"""
}
}
source_config {
desc {
en: """Source config"""
zh: """数据源配置"""
}
label {
en: """source_config"""
zh: """数据源配置"""
}
}
source {
desc {
en: """Authorization source"""
zh: """鉴权数据源"""
}
label {
en: """source"""
zh: """数据源"""
}
}
source_config {
desc {
en: """Source config"""
zh: """数据源配置"""
}
label {
en: """source_config"""
zh: """数据源配置"""
}
}
source_type {
desc {
en: """Authorization type"""
zh: """数据源类型"""
}
label {
en: """source_type"""
zh: """数据源类型"""
}
}
}

View File

@ -0,0 +1,349 @@
emqx_authz_schema {
sources {
desc {
en: """
Authorization data sources.<br>
An array of authorization (ACL) data providers.
It is designed as an array, not a hash-map, so the sources can be
ordered to form a chain of access controls.<br>
When authorizing a 'publish' or 'subscribe' action, the configured
sources are checked in order. When checking an ACL source,
in case the client (identified by username or client ID) is not found,
it moves on to the next source. And it stops immediately
once an 'allow' or 'deny' decision is returned.<br>
If the client is not found in any of the sources,
the default action configured in 'authorization.no_match' is applied.<br>
NOTE:
The source elements are identified by their 'type'.
It is NOT allowed to configure two or more sources of the same type.
"""
zh: """"""
}
label {
en: """sources"""
zh: """"""
}
}
authorization {
desc {
en: """Configuration related to the client authorization."""
zh: """"""
}
label {
en: """authorization"""
zh: """授权"""
}
}
enable {
desc {
en: """Set to <code>true</code> or <code>false</code> to disable this ACL provider"""
zh: """设为 <code>true</code> 或 <code>false</code> 以启用或禁用此访问控制数据源"""
}
label {
en: """enable"""
zh: """enable"""
}
}
type {
desc {
en: """Backend type."""
zh: """数据后端类型"""
}
label {
en: """type"""
zh: """type"""
}
}
#==== authz_file
file {
desc {
en: """Authorization using a static file."""
zh: """使用静态文件鉴权"""
}
label {
en: """file"""
zh: """文件"""
}
}
path {
desc {
en: """
Path to the file which contains the ACL rules.<br>
If the file provisioned before starting EMQX node,
it can be placed anywhere as long as EMQX has read access to it.
In case the rule-set is created from EMQX dashboard or management API,
the file will be placed in `authz` subdirectory inside EMQX's `data_dir`,
and the new rules will override all rules from the old config file.
"""
zh: """"""
}
label {
en: """path"""
zh: """path"""
}
}
#==== authz_http
http_get {
desc {
en: """Authorization using an external HTTP server (via GET requests)."""
zh: """使用外部 HTTP 服务器鉴权(GET 请求)."""
}
label {
en: """http_get"""
zh: """http_get"""
}
}
http_post {
desc {
en: """Authorization using an external HTTP server (via POST requests)."""
zh: """使用外部 HTTP 服务器鉴权(POST 请求)."""
}
label {
en: """http_post"""
zh: """http_post"""
}
}
method {
desc {
en: """HTTP method."""
zh: """HTTP 请求方法"""
}
label {
en: """method"""
zh: """method"""
}
}
url {
desc {
en: """URL of the auth server."""
zh: """认证服务器 URL"""
}
label {
en: """url"""
zh: """url"""
}
}
headers {
desc {
en: """List of HTTP headers."""
zh: """"""
}
label {
en: """headers"""
zh: """请求头"""
}
}
headers_no_content_type {
desc {
en: """List of HTTP headers (without `content_type`)."""
zh: """"""
}
label {
en: """headers_no_content_type"""
zh: """请求头(无 content-type)"""
}
}
body {
desc {
en: """HTTP request body."""
zh: """HTTP 请求体"""
}
label {
en: """body"""
zh: """请求体"""
}
}
request_timeout {
desc {
en: """Request timeout."""
zh: """请求超时时间"""
}
label {
en: """request_timeout"""
zh: """请求超时"""
}
}
#==== authz_mnesia
mnesia {
desc {
en: """Authorization using a built-in database (mnesia)."""
zh: """使用内部数据库鉴权 (mnesia)."""
}
label {
en: """mnesia"""
zh: """mnesia"""
}
}
#==== authz_mongo
mongo_single {
desc {
en: """Authorization using a single MongoDB instance."""
zh: """使用 MongoDB 鉴权(单实例)"""
}
label {
en: """mongo_single"""
zh: """mongo_single"""
}
}
mongo_rs {
desc {
en: """Authorization using a MongoDB replica set."""
zh: """使用 MongoDB 鉴权(副本集模式)"""
}
label {
en: """mongo_rs"""
zh: """mongo_rs"""
}
}
mongo_sharded {
desc {
en: """Authorization using a sharded MongoDB cluster."""
zh: """使用 MongoDB 鉴权(分片集群模式)"""
}
label {
en: """mongo_sharded"""
zh: """mongo_sharded"""
}
}
collection {
desc {
en: """`MongoDB` collection containing the authorization data."""
zh: """`MongoDB` 鉴权数据集"""
}
label {
en: """collection"""
zh: """数据集"""
}
}
selector {
desc {
en: """
Statement that is executed during the authorize process.
Commands can support following wildcards:\n
- `${username}`: substituted with client's username\n
- `${clientid}`: substituted with the clientid
"""
zh: """
鉴权过程中所使用的查询命令。
查询命令支持如下占位符:
- `${username}`: 代替客户端的用户名
- `${clientid}`: 代替客户端的客户端标识符"""
}
label {
en: """selector"""
zh: """selector"""
}
}
#==== authz_mysql
mysql {
desc {
en: """Authorization using a MySQL database."""
zh: """使用 MySOL 数据库鉴权"""
}
label {
en: """mysql"""
zh: """mysql"""
}
}
#==== authz_pgsql
postgresql {
desc {
en: """Authorization using a PostgreSQL database."""
zh: """使用 PostgreSQL 数据库鉴权"""
}
label {
en: """postgresql"""
zh: """postgresql"""
}
}
#==== authz_redis
redis_single {
desc {
en: """Authorization using a single Redis instance."""
zh: """使用 Redis 鉴权(单实例)"""
}
label {
en: """redis_single"""
zh: """redis_single"""
}
}
redis_sentinel {
desc {
en: """Authorization using a Redis Sentinel."""
zh: """使用 Redis 鉴权(哨兵模式)"""
}
label {
en: """redis_sentinel"""
zh: """redis_sentinel"""
}
}
redis_cluster {
desc {
en: """Authorization using a Redis cluster."""
zh: """使用 Redis 鉴权(集群模式)"""
}
label {
en: """redis_cluster"""
zh: """redis_cluster"""
}
}
cmd {
desc {
en: """Database query used to retrieve authorization data."""
zh: """访问控制数据查查询命令"""
}
label {
en: """cmd"""
zh: """查询命令"""
}
}
#==== common field for DBs (except redis)
query {
desc {
en: """Database query used to retrieve authorization data."""
zh: """访问控制数据查询语句/查询命令"""
}
label {
en: """query"""
zh: """查询语句"""
}
}
}

View File

@ -18,6 +18,8 @@
-behaviour(minirest_api). -behaviour(minirest_api).
-include_lib("hocon/include/hoconsc.hrl").
-export([ -export([
api_spec/0, api_spec/0,
paths/0, paths/0,
@ -47,7 +49,7 @@ schema("/authorization/cache") ->
'operationId' => clean_cache, 'operationId' => clean_cache,
delete => delete =>
#{ #{
description => <<"Clean all authorization cache in the cluster.">>, description => ?DESC(authorization_cache_delete),
responses => responses =>
#{ #{
204 => <<"No Content">>, 204 => <<"No Content">>,

View File

@ -20,7 +20,7 @@
-include("emqx_authz.hrl"). -include("emqx_authz.hrl").
-include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/logger.hrl").
-include_lib("typerefl/include/types.hrl"). -include_lib("hocon/include/hoconsc.hrl").
-import(hoconsc, [mk/1, mk/2, ref/1, ref/2, array/1, enum/1]). -import(hoconsc, [mk/1, mk/2, ref/1, ref/2, array/1, enum/1]).
@ -87,7 +87,7 @@ schema("/authorization/sources/built_in_database/username") ->
get => get =>
#{ #{
tags => [<<"authorization">>], tags => [<<"authorization">>],
description => <<"Show the list of record for username">>, description => ?DESC(users_username_get),
parameters => parameters =>
[ [
ref(emqx_dashboard_swagger, page), ref(emqx_dashboard_swagger, page),
@ -96,7 +96,7 @@ schema("/authorization/sources/built_in_database/username") ->
mk(binary(), #{ mk(binary(), #{
in => query, in => query,
required => false, required => false,
desc => <<"Fuzzy search `username` as substring">> desc => ?DESC(fuzzy_username)
})} })}
], ],
responses => responses =>
@ -110,7 +110,7 @@ schema("/authorization/sources/built_in_database/username") ->
post => post =>
#{ #{
tags => [<<"authorization">>], tags => [<<"authorization">>],
description => <<"Add new records for username">>, description => ?DESC(users_username_post),
'requestBody' => swagger_with_example( 'requestBody' => swagger_with_example(
{rules_for_username, ?TYPE_ARRAY}, {rules_for_username, ?TYPE_ARRAY},
{username, ?POST_ARRAY_EXAMPLE} {username, ?POST_ARRAY_EXAMPLE}
@ -130,7 +130,7 @@ schema("/authorization/sources/built_in_database/clientid") ->
get => get =>
#{ #{
tags => [<<"authorization">>], tags => [<<"authorization">>],
description => <<"Show the list of record for clientid">>, description => ?DESC(users_clientid_get),
parameters => parameters =>
[ [
ref(emqx_dashboard_swagger, page), ref(emqx_dashboard_swagger, page),
@ -141,7 +141,7 @@ schema("/authorization/sources/built_in_database/clientid") ->
#{ #{
in => query, in => query,
required => false, required => false,
desc => <<"Fuzzy search `clientid` as substring">> desc => ?DESC(fuzzy_clientid)
} }
)} )}
], ],
@ -156,7 +156,7 @@ schema("/authorization/sources/built_in_database/clientid") ->
post => post =>
#{ #{
tags => [<<"authorization">>], tags => [<<"authorization">>],
description => <<"Add new records for clientid">>, description => ?DESC(users_clientid_post),
'requestBody' => swagger_with_example( 'requestBody' => swagger_with_example(
{rules_for_clientid, ?TYPE_ARRAY}, {rules_for_clientid, ?TYPE_ARRAY},
{clientid, ?POST_ARRAY_EXAMPLE} {clientid, ?POST_ARRAY_EXAMPLE}
@ -176,7 +176,7 @@ schema("/authorization/sources/built_in_database/username/:username") ->
get => get =>
#{ #{
tags => [<<"authorization">>], tags => [<<"authorization">>],
description => <<"Get record info for username">>, description => ?DESC(user_username_get),
parameters => [ref(username)], parameters => [ref(username)],
responses => responses =>
#{ #{
@ -192,7 +192,7 @@ schema("/authorization/sources/built_in_database/username/:username") ->
put => put =>
#{ #{
tags => [<<"authorization">>], tags => [<<"authorization">>],
description => <<"Set record for username">>, description => ?DESC(user_username_put),
parameters => [ref(username)], parameters => [ref(username)],
'requestBody' => swagger_with_example( 'requestBody' => swagger_with_example(
{rules_for_username, ?TYPE_REF}, {rules_for_username, ?TYPE_REF},
@ -209,7 +209,7 @@ schema("/authorization/sources/built_in_database/username/:username") ->
delete => delete =>
#{ #{
tags => [<<"authorization">>], tags => [<<"authorization">>],
description => <<"Delete one record for username">>, description => ?DESC(user_username_delete),
parameters => [ref(username)], parameters => [ref(username)],
responses => responses =>
#{ #{
@ -229,7 +229,7 @@ schema("/authorization/sources/built_in_database/clientid/:clientid") ->
get => get =>
#{ #{
tags => [<<"authorization">>], tags => [<<"authorization">>],
description => <<"Get record info for clientid">>, description => ?DESC(user_clientid_get),
parameters => [ref(clientid)], parameters => [ref(clientid)],
responses => responses =>
#{ #{
@ -245,7 +245,7 @@ schema("/authorization/sources/built_in_database/clientid/:clientid") ->
put => put =>
#{ #{
tags => [<<"authorization">>], tags => [<<"authorization">>],
description => <<"Set record for clientid">>, description => ?DESC(user_clientid_put),
parameters => [ref(clientid)], parameters => [ref(clientid)],
'requestBody' => swagger_with_example( 'requestBody' => swagger_with_example(
{rules_for_clientid, ?TYPE_REF}, {rules_for_clientid, ?TYPE_REF},
@ -262,7 +262,7 @@ schema("/authorization/sources/built_in_database/clientid/:clientid") ->
delete => delete =>
#{ #{
tags => [<<"authorization">>], tags => [<<"authorization">>],
description => <<"Delete one record for clientid">>, description => ?DESC(user_clientid_delete),
parameters => [ref(clientid)], parameters => [ref(clientid)],
responses => responses =>
#{ #{
@ -282,17 +282,14 @@ schema("/authorization/sources/built_in_database/all") ->
get => get =>
#{ #{
tags => [<<"authorization">>], tags => [<<"authorization">>],
description => <<"Show the list of rules for all">>, description => ?DESC(rules_for_all_get),
responses => responses =>
#{200 => swagger_with_example({rules, ?TYPE_REF}, {all, ?PUT_MAP_EXAMPLE})} #{200 => swagger_with_example({rules, ?TYPE_REF}, {all, ?PUT_MAP_EXAMPLE})}
}, },
post => post =>
#{ #{
tags => [<<"authorization">>], tags => [<<"authorization">>],
description => << description => ?DESC(rules_for_all_post),
"Create/Update the list of rules for all. "
"Set a empty list to clean up rules"
>>,
'requestBody' => 'requestBody' =>
swagger_with_example({rules, ?TYPE_REF}, {all, ?PUT_MAP_EXAMPLE}), swagger_with_example({rules, ?TYPE_REF}, {all, ?PUT_MAP_EXAMPLE}),
responses => responses =>
@ -310,7 +307,7 @@ schema("/authorization/sources/built_in_database/purge-all") ->
delete => delete =>
#{ #{
tags => [<<"authorization">>], tags => [<<"authorization">>],
description => <<"Purge all records">>, description => ?DESC(purge_all_delete),
responses => responses =>
#{ #{
204 => <<"Deleted">>, 204 => <<"Deleted">>,
@ -328,7 +325,7 @@ fields(rule_item) ->
string(), string(),
#{ #{
required => true, required => true,
desc => <<"Rule on specific topic">>, desc => ?DESC(topic),
example => <<"test/topic/1">> example => <<"test/topic/1">>
} }
)}, )},
@ -336,7 +333,7 @@ fields(rule_item) ->
mk( mk(
enum([allow, deny]), enum([allow, deny]),
#{ #{
desc => <<"Permission">>, desc => ?DESC(permission),
required => true, required => true,
example => allow example => allow
} }
@ -345,9 +342,9 @@ fields(rule_item) ->
mk( mk(
enum([publish, subscribe, all]), enum([publish, subscribe, all]),
#{ #{
desc => ?DESC(action),
required => true, required => true,
example => publish, example => publish
desc => <<"Authorized action">>
} }
)} )}
]; ];
@ -359,7 +356,7 @@ fields(clientid) ->
#{ #{
in => path, in => path,
required => true, required => true,
desc => <<"ClientID">>, desc => ?DESC(clientid),
example => <<"client1">> example => <<"client1">>
} }
)} )}
@ -372,7 +369,7 @@ fields(username) ->
#{ #{
in => path, in => path,
required => true, required => true,
desc => <<"Username">>, desc => ?DESC(username),
example => <<"user1">> example => <<"user1">>
} }
)} )}

View File

@ -17,7 +17,7 @@
-module(emqx_authz_api_schema). -module(emqx_authz_api_schema).
-include("emqx_authz.hrl"). -include("emqx_authz.hrl").
-include_lib("typerefl/include/types.hrl"). -include_lib("hocon/include/hoconsc.hrl").
-include_lib("emqx_connector/include/emqx_connector.hrl"). -include_lib("emqx_connector/include/emqx_connector.hrl").
-import(hoconsc, [mk/2, enum/1]). -import(hoconsc, [mk/2, enum/1]).
@ -32,14 +32,26 @@
%% Hocon Schema %% Hocon Schema
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
fields(file) ->
authz_common_fields(file) ++
[
{rules, #{
type => binary(),
required => true,
example =>
<<"{allow,{username,\"^dashboard?\"},", "subscribe,[\"$SYS/#\"]}.\n",
"{allow,{ipaddr,\"127.0.0.1\"},all,[\"$SYS/#\",\"#\"]}.">>,
desc => ?DESC(rules)
}}
];
fields(http_get) -> fields(http_get) ->
[ [
{method, #{type => get, default => get, required => true}}, {method, #{type => get, default => get, required => true, desc => ?DESC(method)}},
{headers, fun headers_no_content_type/1} {headers, fun headers_no_content_type/1}
] ++ authz_http_common_fields(); ] ++ authz_http_common_fields();
fields(http_post) -> fields(http_post) ->
[ [
{method, #{type => post, default => post, required => true}}, {method, #{type => post, default => post, required => true, desc => ?DESC(method)}},
{headers, fun headers/1} {headers, fun headers/1}
] ++ authz_http_common_fields(); ] ++ authz_http_common_fields();
fields(built_in_database) -> fields(built_in_database) ->
@ -55,11 +67,11 @@ fields(mongo_sharded) ->
emqx_connector_mongo:fields(sharded); emqx_connector_mongo:fields(sharded);
fields(mysql) -> fields(mysql) ->
authz_common_fields(mysql) ++ authz_common_fields(mysql) ++
[{query, mk(binary(), #{required => true})}] ++ [{query, query()}] ++
proplists:delete(prepare_statement, emqx_connector_mysql:fields(config)); proplists:delete(prepare_statement, emqx_connector_mysql:fields(config));
fields(postgresql) -> fields(postgresql) ->
authz_common_fields(postgresql) ++ authz_common_fields(postgresql) ++
[{query, mk(binary(), #{required => true})}] ++ [{query, query()}] ++
proplists:delete(prepare_statement, emqx_connector_pgsql:fields(config)); proplists:delete(prepare_statement, emqx_connector_pgsql:fields(config));
fields(redis_single) -> fields(redis_single) ->
authz_redis_common_fields() ++ authz_redis_common_fields() ++
@ -70,24 +82,13 @@ fields(redis_sentinel) ->
fields(redis_cluster) -> fields(redis_cluster) ->
authz_redis_common_fields() ++ authz_redis_common_fields() ++
emqx_connector_redis:fields(cluster); emqx_connector_redis:fields(cluster);
fields(file) ->
authz_common_fields(file) ++
[
{rules, #{
type => binary(),
required => true,
example =>
<<"{allow,{username,\"^dashboard?\"},", "subscribe,[\"$SYS/#\"]}.\n",
"{allow,{ipaddr,\"127.0.0.1\"},all,[\"$SYS/#\",\"#\"]}.">>
}}
];
fields(position) -> fields(position) ->
[ [
{position, {position,
mk( mk(
string(), string(),
#{ #{
desc => <<"Where to place the source">>, desc => ?DESC(position),
required => true, required => true,
in => body in => body
} }
@ -102,7 +103,8 @@ authz_http_common_fields() ->
[ [
{url, fun url/1}, {url, fun url/1},
{body, map([{fuzzy, term(), binary()}])}, {body, map([{fuzzy, term(), binary()}])},
{request_timeout, mk_duration("Request timeout", #{default => "30s"})} {request_timeout,
mk_duration("Request timeout", #{default => "30s", desc => ?DESC(request_timeout)})}
] ++ ] ++
maps:to_list( maps:to_list(
maps:without( maps:without(
@ -117,12 +119,13 @@ authz_http_common_fields() ->
url(type) -> binary(); url(type) -> binary();
url(validator) -> [?NOT_EMPTY("the value of the field 'url' cannot be empty")]; url(validator) -> [?NOT_EMPTY("the value of the field 'url' cannot be empty")];
url(required) -> true; url(required) -> true;
url(desc) -> ?DESC(?FUNCTION_NAME);
url(_) -> undefined. url(_) -> undefined.
headers(type) -> headers(type) ->
map(); map();
headers(desc) -> headers(desc) ->
"List of HTTP headers."; ?DESC(?FUNCTION_NAME);
headers(converter) -> headers(converter) ->
fun(Headers) -> fun(Headers) ->
maps:merge(default_headers(), transform_header_name(Headers)) maps:merge(default_headers(), transform_header_name(Headers))
@ -135,7 +138,7 @@ headers(_) ->
headers_no_content_type(type) -> headers_no_content_type(type) ->
map(); map();
headers_no_content_type(desc) -> headers_no_content_type(desc) ->
"List of HTTP headers."; ?DESC(?FUNCTION_NAME);
headers_no_content_type(converter) -> headers_no_content_type(converter) ->
fun(Headers) -> fun(Headers) ->
maps:merge(default_headers_no_content_type(), transform_header_name(Headers)) maps:merge(default_headers_no_content_type(), transform_header_name(Headers))
@ -182,17 +185,14 @@ authz_mongo_common_fields() ->
]. ].
collection(type) -> binary(); collection(type) -> binary();
collection(desc) -> "Collection used to store authentication data."; collection(desc) -> ?DESC(?FUNCTION_NAME);
collection(required) -> true; collection(required) -> true;
collection(_) -> undefined. collection(_) -> undefined.
selector(type) -> selector(type) ->
map(); map();
selector(desc) -> selector(desc) ->
"Statement that is executed during the authentication process. " ?DESC(?FUNCTION_NAME);
"Commands can support following wildcards:\n"
" - `${username}`: substituted with client's username\n"
" - `${clientid}`: substituted with the clientid";
selector(_) -> selector(_) ->
undefined. undefined.
@ -205,6 +205,7 @@ authz_redis_common_fields() ->
{cmd, {cmd,
mk(binary(), #{ mk(binary(), #{
required => true, required => true,
desc => ?DESC(cmd),
example => <<"HGETALL mqtt_authz">> example => <<"HGETALL mqtt_authz">>
})} })}
]. ].
@ -216,18 +217,35 @@ authz_common_fields(Type) when is_atom(Type) ->
[ [
{enable, fun enable/1}, {enable, fun enable/1},
{type, #{ {type, #{
type => enum([Type]), type => Type,
default => Type, default => Type,
required => true, required => true,
desc => ?DESC(type),
in => body in => body
}} }}
]. ].
enable(type) -> boolean(); enable(type) -> boolean();
enable(default) -> true; enable(default) -> true;
enable(desc) -> "Set to <code>false</code> to disable this auth provider"; enable(desc) -> ?DESC(?FUNCTION_NAME);
enable(_) -> undefined. enable(_) -> undefined.
%%------------------------------------------------------------------------------
%% Authz DB query
query() ->
#{
type => binary(),
desc => ?DESC(query),
required => true,
validator => fun(S) ->
case size(S) > 0 of
true -> ok;
_ -> {error, "Request query"}
end
end
}.
%%------------------------------------------------------------------------------ %%------------------------------------------------------------------------------
%% Internal funcs %% Internal funcs

View File

@ -18,6 +18,8 @@
-behaviour(minirest_api). -behaviour(minirest_api).
-include_lib("hocon/include/hoconsc.hrl").
-import(hoconsc, [mk/1, ref/2]). -import(hoconsc, [mk/1, ref/2]).
-export([ -export([
@ -45,13 +47,13 @@ schema("/authorization/settings") ->
'operationId' => settings, 'operationId' => settings,
get => get =>
#{ #{
description => <<"Get authorization settings">>, description => ?DESC(authorization_settings_get),
responses => responses =>
#{200 => ref_authz_schema()} #{200 => ref_authz_schema()}
}, },
put => put =>
#{ #{
description => <<"Update authorization settings">>, description => ?DESC(authorization_settings_put),
'requestBody' => ref_authz_schema(), 'requestBody' => ref_authz_schema(),
responses => responses =>
#{ #{

View File

@ -18,9 +18,9 @@
-behaviour(minirest_api). -behaviour(minirest_api).
-include_lib("typerefl/include/types.hrl").
-include("emqx_authz.hrl"). -include("emqx_authz.hrl").
-include_lib("emqx/include/logger.hrl"). -include_lib("emqx/include/logger.hrl").
-include_lib("hocon/include/hoconsc.hrl").
-import(hoconsc, [mk/1, mk/2, ref/2, array/1, enum/1]). -import(hoconsc, [mk/1, mk/2, ref/2, array/1, enum/1]).
@ -63,27 +63,26 @@ paths() ->
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
%% Schema for each URI %% Schema for each URI
%%-------------------------------------------------------------------- %%--------------------------------------------------------------------
schema("/authorization/sources") -> schema("/authorization/sources") ->
#{ #{
'operationId' => sources, 'operationId' => sources,
get => get =>
#{ #{
description => <<"List all authorization sources">>, description => ?DESC(authorization_sources_get),
responses => responses =>
#{ #{
200 => mk( 200 => mk(
array(hoconsc:union(authz_sources_type_refs())), array(hoconsc:union(authz_sources_type_refs())),
#{desc => <<"Authorization source">>} #{desc => ?DESC(sources)}
) )
} }
}, },
post => post =>
#{ #{
description => <<"Add a new source">>, description => ?DESC(authorization_sources_post),
'requestBody' => mk( 'requestBody' => mk(
hoconsc:union(authz_sources_type_refs()), hoconsc:union(authz_sources_type_refs()),
#{desc => <<"Source config">>} #{desc => ?DESC(source_config)}
), ),
responses => responses =>
#{ #{
@ -100,20 +99,20 @@ schema("/authorization/sources/:type") ->
'operationId' => source, 'operationId' => source,
get => get =>
#{ #{
description => <<"Get a authorization source">>, description => ?DESC(authorization_sources_type_get),
parameters => parameters_field(), parameters => parameters_field(),
responses => responses =>
#{ #{
200 => mk( 200 => mk(
hoconsc:union(authz_sources_type_refs()), hoconsc:union(authz_sources_type_refs()),
#{desc => <<"Authorization source">>} #{desc => ?DESC(source)}
), ),
404 => emqx_dashboard_swagger:error_codes([?NOT_FOUND], <<"Not Found">>) 404 => emqx_dashboard_swagger:error_codes([?NOT_FOUND], <<"Not Found">>)
} }
}, },
put => put =>
#{ #{
description => <<"Update source">>, description => ?DESC(authorization_sources_type_put),
parameters => parameters_field(), parameters => parameters_field(),
'requestBody' => mk(hoconsc:union(authz_sources_type_refs())), 'requestBody' => mk(hoconsc:union(authz_sources_type_refs())),
responses => responses =>
@ -124,7 +123,7 @@ schema("/authorization/sources/:type") ->
}, },
delete => delete =>
#{ #{
description => <<"Delete source">>, description => ?DESC(authorization_sources_type_delete),
parameters => parameters_field(), parameters => parameters_field(),
responses => responses =>
#{ #{
@ -138,7 +137,7 @@ schema("/authorization/sources/:type/status") ->
'operationId' => source_status, 'operationId' => source_status,
get => get =>
#{ #{
description => <<"Get a authorization source">>, description => ?DESC(authorization_sources_type_status_get),
parameters => parameters_field(), parameters => parameters_field(),
responses => responses =>
#{ #{
@ -158,7 +157,7 @@ schema("/authorization/sources/:type/move") ->
'operationId' => move_source, 'operationId' => move_source,
post => post =>
#{ #{
description => <<"Change the order of sources">>, description => ?DESC(authorization_sources_type_move_post),
parameters => parameters_field(), parameters => parameters_field(),
'requestBody' => 'requestBody' =>
emqx_dashboard_swagger:schema_with_examples( emqx_dashboard_swagger:schema_with_examples(
@ -508,7 +507,7 @@ parameters_field() ->
{type, {type,
mk( mk(
enum(?API_SCHEMA_MODULE:authz_sources_types(simple)), enum(?API_SCHEMA_MODULE:authz_sources_types(simple)),
#{in => path, desc => <<"Authorization type">>} #{in => path, desc => ?DESC(source_type)}
)} )}
]. ].

View File

@ -99,7 +99,7 @@ authorize(
} = Client, } = Client,
PubSub, PubSub,
Topic, Topic,
#{type := 'built_in_database'} #{type := built_in_database}
) -> ) ->
Rules = Rules =
case mnesia:dirty_read(?ACL_TABLE, {?ACL_TABLE_CLIENTID, Clientid}) of case mnesia:dirty_read(?ACL_TABLE, {?ACL_TABLE_CLIENTID, Clientid}) of

View File

@ -17,7 +17,7 @@
-module(emqx_authz_schema). -module(emqx_authz_schema).
-include("emqx_authz.hrl"). -include("emqx_authz.hrl").
-include_lib("typerefl/include/types.hrl"). -include_lib("hocon/include/hoconsc.hrl").
-include_lib("emqx_connector/include/emqx_connector.hrl"). -include_lib("emqx_connector/include/emqx_connector.hrl").
-reflect_type([ -reflect_type([
@ -71,134 +71,104 @@ fields("authorization") ->
] ]
), ),
default => [], default => [],
desc => desc => ?DESC(sources)
"\n"
"Authorization data sources.<br>\n"
"An array of authorization (ACL) data providers.\n"
"It is designed as an array, not a hash-map, so the sources can be\n"
"ordered to form a chain of access controls.<br>\n"
"\n"
"When authorizing a 'publish' or 'subscribe' action, the configured\n"
"sources are checked in order. When checking an ACL source,\n"
"in case the client (identified by username or client ID) is not found,\n"
"it moves on to the next source. And it stops immediately\n"
"once an 'allow' or 'deny' decision is returned.<br>\n"
"\n"
"If the client is not found in any of the sources,\n"
"the default action configured in 'authorization.no_match' is applied.<br>\n"
"\n"
"NOTE:\n"
"The source elements are identified by their 'type'.\n"
"It is NOT allowed to configure two or more sources of the same type.\n"
}} }}
]; ];
fields(file) -> fields(file) ->
[ authz_common_fields(file) ++
{type, #{type => file, required => true, desc => "Backend type."}}, [{path, #{type => string(), required => true, desc => ?DESC(path)}}];
{enable, #{
type => boolean(),
default => true,
desc => "Enable this backend."
}},
{path, #{
type => string(),
required => true,
desc =>
"\n"
"Path to the file which contains the ACL rules.<br>\n"
"If the file provisioned before starting EMQX node,\n"
"it can be placed anywhere as long as EMQX has read access to it.\n"
"\n"
"In case the rule-set is created from EMQX dashboard or management API,\n"
"the file will be placed in `authz` subdirectory inside EMQX's `data_dir`,\n"
"and the new rules will override all rules from the old config file.\n"
}}
];
fields(http_get) -> fields(http_get) ->
authz_common_fields(http) ++
http_common_fields() ++
[ [
{method, #{type => get, default => get, required => true, desc => "HTTP method."}}, {method, #{type => get, default => get, required => true, desc => ?DESC(method)}},
{headers, fun headers_no_content_type/1} {headers, fun headers_no_content_type/1}
] ++ http_common_fields();
fields(http_post) ->
[
{method, #{type => post, default => post, required => true, desc => "HTTP method."}},
{headers, fun headers/1}
] ++ http_common_fields();
fields(mnesia) ->
[
{type, #{type => 'built_in_database', required => true, desc => "Backend type."}},
{enable, #{
type => boolean(),
default => true,
desc => "Enable this backend."
}}
]; ];
fields(http_post) ->
authz_common_fields(http) ++
http_common_fields() ++
[
{method, #{type => post, default => post, required => true, desc => ?DESC(method)}},
{headers, fun headers/1}
];
fields(mnesia) ->
authz_common_fields(built_in_database);
fields(mongo_single) -> fields(mongo_single) ->
mongo_common_fields() ++ emqx_connector_mongo:fields(single); authz_common_fields(mongodb) ++
mongo_common_fields() ++
emqx_connector_mongo:fields(single);
fields(mongo_rs) -> fields(mongo_rs) ->
mongo_common_fields() ++ emqx_connector_mongo:fields(rs); authz_common_fields(mongodb) ++
mongo_common_fields() ++
emqx_connector_mongo:fields(rs);
fields(mongo_sharded) -> fields(mongo_sharded) ->
mongo_common_fields() ++ emqx_connector_mongo:fields(sharded); authz_common_fields(mongodb) ++
mongo_common_fields() ++
emqx_connector_mongo:fields(sharded);
fields(mysql) -> fields(mysql) ->
authz_common_fields(mysql) ++
connector_fields(mysql) ++ connector_fields(mysql) ++
[{query, query()}]; [{query, query()}];
fields(postgresql) -> fields(postgresql) ->
[ authz_common_fields(postgresql) ++
{query, query()}, emqx_connector_pgsql:fields(config) ++
{type, #{type => postgresql, required => true, desc => "Backend type."}}, [{query, query()}];
{enable, #{
type => boolean(),
desc => "Enable this backend.",
default => true
}}
] ++ emqx_connector_pgsql:fields(config);
fields(redis_single) -> fields(redis_single) ->
authz_common_fields(redis) ++
connector_fields(redis, single) ++ connector_fields(redis, single) ++
[{cmd, query()}]; [{cmd, cmd()}];
fields(redis_sentinel) -> fields(redis_sentinel) ->
authz_common_fields(redis) ++
connector_fields(redis, sentinel) ++ connector_fields(redis, sentinel) ++
[{cmd, query()}]; [{cmd, cmd()}];
fields(redis_cluster) -> fields(redis_cluster) ->
authz_common_fields(redis) ++
connector_fields(redis, cluster) ++ connector_fields(redis, cluster) ++
[{cmd, query()}]. [{cmd, cmd()}].
desc("authorization") -> desc(?CONF_NS) ->
"Configuration related to the client authorization."; ?DESC(?CONF_NS);
desc(file) -> desc(file) ->
"Authorization using a static file."; ?DESC(file);
desc(http_get) -> desc(http_get) ->
"Authorization using an external HTTP server (via GET requests)."; ?DESC(http_get);
desc(http_post) -> desc(http_post) ->
"Authorization using an external HTTP server (via POST requests)."; ?DESC(http_post);
desc(mnesia) -> desc(mnesia) ->
"Authorization using a built-in database (mnesia)."; ?DESC(mnesia);
desc(mongo_single) -> desc(mongo_single) ->
"Authorization using a single MongoDB instance."; ?DESC(mongo_single);
desc(mongo_rs) -> desc(mongo_rs) ->
"Authorization using a MongoDB replica set."; ?DESC(mongo_rs);
desc(mongo_sharded) -> desc(mongo_sharded) ->
"Authorization using a sharded MongoDB cluster."; ?DESC(mongo_sharded);
desc(mysql) -> desc(mysql) ->
"Authorization using a MySQL database."; ?DESC(mysql);
desc(postgresql) -> desc(postgresql) ->
"Authorization using a PostgreSQL database."; ?DESC(postgresql);
desc(redis_single) -> desc(redis_single) ->
"Authorization using a single Redis instance."; ?DESC(redis_single);
desc(redis_sentinel) -> desc(redis_sentinel) ->
"Authorization using a Redis Sentinel."; ?DESC(redis_sentinel);
desc(redis_cluster) -> desc(redis_cluster) ->
"Authorization using a Redis cluster."; ?DESC(redis_cluster);
desc(_) -> desc(_) ->
undefined. undefined.
authz_common_fields(Type) ->
[
{type, #{type => Type, required => true, desc => ?DESC(type)}},
{enable, #{type => boolean(), default => true, desc => ?DESC(enable)}}
].
http_common_fields() -> http_common_fields() ->
[ [
{url, fun url/1}, {url, fun url/1},
{request_timeout, {request_timeout,
emqx_schema:mk_duration("Request timeout", #{ emqx_schema:mk_duration("Request timeout", #{
default => "30s", desc => "Request timeout." default => "30s", desc => ?DESC(request_timeout)
})}, })},
{body, #{type => map(), required => false, desc => "HTTP request body."}} {body, #{type => map(), required => false, desc => ?DESC(body)}}
] ++ ] ++
maps:to_list( maps:to_list(
maps:without( maps:without(
@ -215,18 +185,12 @@ mongo_common_fields() ->
{collection, #{ {collection, #{
type => atom(), type => atom(),
required => true, required => true,
desc => "`MongoDB` collection containing the authorization data." desc => ?DESC(collection)
}}, }},
{selector, #{ {selector, #{
type => map(), type => map(),
required => true, required => true,
desc => "MQL query used to select the authorization record." desc => ?DESC(selector)
}},
{type, #{type => mongodb, required => true, desc => "Database backend."}},
{enable, #{
type => boolean(),
default => true,
desc => "Enable or disable the backend."
}} }}
]. ].
@ -238,7 +202,7 @@ validations() ->
headers(type) -> headers(type) ->
list({binary(), binary()}); list({binary(), binary()});
headers(desc) -> headers(desc) ->
"List of HTTP headers."; ?DESC(?FUNCTION_NAME);
headers(converter) -> headers(converter) ->
fun(Headers) -> fun(Headers) ->
maps:to_list(maps:merge(default_headers(), transform_header_name(Headers))) maps:to_list(maps:merge(default_headers(), transform_header_name(Headers)))
@ -251,7 +215,7 @@ headers(_) ->
headers_no_content_type(type) -> headers_no_content_type(type) ->
list({binary(), binary()}); list({binary(), binary()});
headers_no_content_type(desc) -> headers_no_content_type(desc) ->
"List of HTTP headers."; ?DESC(?FUNCTION_NAME);
headers_no_content_type(converter) -> headers_no_content_type(converter) ->
fun(Headers) -> fun(Headers) ->
maps:to_list(maps:merge(default_headers_no_content_type(), transform_header_name(Headers))) maps:to_list(maps:merge(default_headers_no_content_type(), transform_header_name(Headers)))
@ -269,7 +233,7 @@ headers_no_content_type(_) ->
undefined. undefined.
url(type) -> binary(); url(type) -> binary();
url(desc) -> "URL of the auth server."; url(desc) -> ?DESC(?FUNCTION_NAME);
url(validator) -> [?NOT_EMPTY("the value of the field 'url' cannot be empty")]; url(validator) -> [?NOT_EMPTY("the value of the field 'url' cannot be empty")];
url(required) -> true; url(required) -> true;
url(_) -> undefined. url(_) -> undefined.
@ -328,7 +292,20 @@ union_array(Item) when is_list(Item) ->
query() -> query() ->
#{ #{
type => binary(), type => binary(),
desc => "Database query used to retrieve authorization data.", desc => ?DESC(query),
required => true,
validator => fun(S) ->
case size(S) > 0 of
true -> ok;
_ -> {error, "Request query"}
end
end
}.
cmd() ->
#{
type => binary(),
desc => ?DESC(cmd),
required => true, required => true,
validator => fun(S) -> validator => fun(S) ->
case size(S) > 0 of case size(S) > 0 of
@ -351,14 +328,7 @@ connector_fields(DB, Fields) ->
error:Reason -> error:Reason ->
erlang:error(Reason) erlang:error(Reason)
end, end,
[ erlang:apply(Mod, fields, [Fields]).
{type, #{type => DB, desc => "Database backend."}},
{enable, #{
type => boolean(),
default => true,
desc => "Enable or disable the backend."
}}
] ++ erlang:apply(Mod, fields, [Fields]).
to_list(A) when is_atom(A) -> to_list(A) when is_atom(A) ->
atom_to_list(A); atom_to_list(A);