Merge branch 'plugins' into dev
This commit is contained in:
commit
8bd867325c
|
@ -0,0 +1,32 @@
|
|||
REBAR?=./rebar
|
||||
|
||||
|
||||
all: build
|
||||
|
||||
|
||||
clean:
|
||||
$(REBAR) clean
|
||||
rm -rf logs
|
||||
rm -rf .eunit
|
||||
rm -f test/*.beam
|
||||
|
||||
|
||||
distclean: clean
|
||||
git clean -fxd
|
||||
|
||||
build: depends
|
||||
$(REBAR) compile
|
||||
|
||||
|
||||
eunit:
|
||||
$(REBAR) eunit skip_deps=true
|
||||
|
||||
|
||||
check: build eunit
|
||||
|
||||
|
||||
%.beam: %.erl
|
||||
erlc -o test/ $<
|
||||
|
||||
|
||||
.PHONY: all clean distclean depends build eunit check
|
|
@ -0,0 +1,49 @@
|
|||
## Overview
|
||||
|
||||
Authentication with user table of MySQL database.
|
||||
|
||||
## etc/plugin.config
|
||||
|
||||
```erlang
|
||||
[
|
||||
{emysql, [
|
||||
{pool, 4},
|
||||
{host, "localhost"},
|
||||
{port, 3306},
|
||||
{username, ""},
|
||||
{password, ""},
|
||||
{database, "mqtt"},
|
||||
{encoding, utf8}
|
||||
]},
|
||||
{emqttd_auth_mysql, [
|
||||
{user_table, mqtt_users},
|
||||
%% plain password only
|
||||
{password_hash, plain},
|
||||
{field_mapper, [
|
||||
{username, username},
|
||||
{password, password}
|
||||
]}
|
||||
]}
|
||||
].
|
||||
```
|
||||
|
||||
## Users Table(Demo)
|
||||
|
||||
Notice: This is a demo table. You could authenticate with any user tables.
|
||||
|
||||
```
|
||||
CREATE TABLE `mqtt_users` (
|
||||
`id` int(11) unsigned NOT NULL AUTO_INCREMENT,
|
||||
`username` varchar(60) DEFAULT NULL,
|
||||
`password` varchar(60) DEFAULT NULL,
|
||||
`salt` varchar(20) DEFAULT NULL,
|
||||
`created` datetime DEFAULT NULL,
|
||||
PRIMARY KEY (`id`),
|
||||
UNIQUE KEY `mqtt_users_username` (`username`)
|
||||
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=utf8;
|
||||
```
|
||||
|
||||
## Load Plugin
|
||||
|
||||
Merge the'etc/plugin.config' to emqttd/etc/plugins.config, and the plugin will be loaded by the broker.
|
||||
|
|
@ -0,0 +1,151 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Hgskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the Kungliga Tekniska
|
||||
* Hgskolan and its contributors.
|
||||
*
|
||||
* 4. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include <config.h>
|
||||
/*RCSID("$Id: base64.c,v 1.1 2005/02/11 07:34:35 jpm Exp jpm $");*/
|
||||
#endif
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include "base64.h"
|
||||
|
||||
static char base64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
|
||||
|
||||
static int pos(char c)
|
||||
{
|
||||
char *p;
|
||||
for(p = base64; *p; p++)
|
||||
if(*p == c)
|
||||
return p - base64;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int base64_encode(const void *data, int size, char **str)
|
||||
{
|
||||
char *s, *p;
|
||||
int i;
|
||||
int c;
|
||||
unsigned char *q;
|
||||
|
||||
p = s = (char*)malloc(size*4/3+4);
|
||||
if (p == NULL)
|
||||
return -1;
|
||||
q = (unsigned char*)data;
|
||||
i=0;
|
||||
for(i = 0; i < size;){
|
||||
c=q[i++];
|
||||
c*=256;
|
||||
if(i < size)
|
||||
c+=q[i];
|
||||
i++;
|
||||
c*=256;
|
||||
if(i < size)
|
||||
c+=q[i];
|
||||
i++;
|
||||
p[0]=base64[(c&0x00fc0000) >> 18];
|
||||
p[1]=base64[(c&0x0003f000) >> 12];
|
||||
p[2]=base64[(c&0x00000fc0) >> 6];
|
||||
p[3]=base64[(c&0x0000003f) >> 0];
|
||||
if(i > size)
|
||||
p[3]='=';
|
||||
if(i > size+1)
|
||||
p[2]='=';
|
||||
p+=4;
|
||||
}
|
||||
*p=0;
|
||||
*str = s;
|
||||
return strlen(s);
|
||||
}
|
||||
|
||||
int base64_decode(const char *str, void *data)
|
||||
{
|
||||
const char *p;
|
||||
unsigned char *q;
|
||||
int c;
|
||||
int x;
|
||||
int done = 0;
|
||||
q=(unsigned char*)data;
|
||||
for(p=str; *p && !done; p+=4){
|
||||
x = pos(p[0]);
|
||||
if(x >= 0)
|
||||
c = x;
|
||||
else{
|
||||
done = 3;
|
||||
break;
|
||||
}
|
||||
c*=64;
|
||||
|
||||
x = pos(p[1]);
|
||||
if(x >= 0)
|
||||
c += x;
|
||||
else
|
||||
return -1;
|
||||
c*=64;
|
||||
|
||||
if(p[2] == '=')
|
||||
done++;
|
||||
else{
|
||||
x = pos(p[2]);
|
||||
if(x >= 0)
|
||||
c += x;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
c*=64;
|
||||
|
||||
if(p[3] == '=')
|
||||
done++;
|
||||
else{
|
||||
if(done)
|
||||
return -1;
|
||||
x = pos(p[3]);
|
||||
if(x >= 0)
|
||||
c += x;
|
||||
else
|
||||
return -1;
|
||||
}
|
||||
if(done < 3)
|
||||
*q++=(c&0x00ff0000)>>16;
|
||||
|
||||
if(done < 2)
|
||||
*q++=(c&0x0000ff00)>>8;
|
||||
if(done < 1)
|
||||
*q++=(c&0x000000ff)>>0;
|
||||
}
|
||||
return q - (unsigned char*)data;
|
||||
}
|
|
@ -0,0 +1,47 @@
|
|||
/*
|
||||
* Copyright (c) 1995, 1996, 1997 Kungliga Tekniska Hgskolan
|
||||
* (Royal Institute of Technology, Stockholm, Sweden).
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
*
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* 3. All advertising materials mentioning features or use of this software
|
||||
* must display the following acknowledgement:
|
||||
* This product includes software developed by the Kungliga Tekniska
|
||||
* Hgskolan and its contributors.
|
||||
*
|
||||
* 4. Neither the name of the Institute nor the names of its contributors
|
||||
* may be used to endorse or promote products derived from this software
|
||||
* without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
/* $Id: base64.h,v 1.1 2005/02/11 07:34:35 jpm Exp jpm $ */
|
||||
|
||||
#ifndef _BASE64_H_
|
||||
#define _BASE64_H_
|
||||
|
||||
int base64_encode(const void *data, int size, char **str);
|
||||
int base64_decode(const char *str, void *data);
|
||||
|
||||
#endif
|
|
@ -0,0 +1,60 @@
|
|||
// This file is part of Jiffy released under the MIT license.
|
||||
// See the LICENSE file for more information.
|
||||
|
||||
#include "emqttd_plugin_mysql_app.h"
|
||||
|
||||
static int
|
||||
load(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
|
||||
{
|
||||
emqttd_plugin_mysql_app_st* st = enif_alloc(sizeof(emqttd_plugin_mysql_app_st));
|
||||
if(st == NULL) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
st->atom_ok = make_atom(env, "ok");
|
||||
st->atom_error = make_atom(env, "error");
|
||||
st->atom_null = make_atom(env, "null");
|
||||
st->atom_true = make_atom(env, "true");
|
||||
st->atom_false = make_atom(env, "false");
|
||||
st->atom_bignum = make_atom(env, "bignum");
|
||||
st->atom_bignum_e = make_atom(env, "bignum_e");
|
||||
st->atom_bigdbl = make_atom(env, "bigdbl");
|
||||
st->atom_partial = make_atom(env, "partial");
|
||||
st->atom_uescape = make_atom(env, "uescape");
|
||||
st->atom_pretty = make_atom(env, "pretty");
|
||||
st->atom_force_utf8 = make_atom(env, "force_utf8");
|
||||
|
||||
// Markers used in encoding
|
||||
st->ref_object = make_atom(env, "$object_ref$");
|
||||
st->ref_array = make_atom(env, "$array_ref$");
|
||||
|
||||
*priv = (void*) st;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
reload(ErlNifEnv* env, void** priv, ERL_NIF_TERM info)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int
|
||||
upgrade(ErlNifEnv* env, void** priv, void** old_priv, ERL_NIF_TERM info)
|
||||
{
|
||||
return load(env, priv, info);
|
||||
}
|
||||
|
||||
static void
|
||||
unload(ErlNifEnv* env, void* priv)
|
||||
{
|
||||
enif_free(priv);
|
||||
return;
|
||||
}
|
||||
|
||||
static ErlNifFunc funcs[] =
|
||||
{
|
||||
{"nif_pbkdf2_check", 2, pbkdf2_check}
|
||||
};
|
||||
|
||||
ERL_NIF_INIT(emqttd_plugin_mysql_app, funcs, &load, &reload, &upgrade, &unload);
|
|
@ -0,0 +1,44 @@
|
|||
// This file is part of Jiffy released under the MIT license.
|
||||
// See the LICENSE file for more information.
|
||||
|
||||
#ifndef EMQTTD_PLUGIN_MYSQL_APP_H
|
||||
#define EMQTTD_PLUGIN_MYSQL_APP_H
|
||||
|
||||
#include "erl_nif.h"
|
||||
|
||||
typedef struct {
|
||||
ERL_NIF_TERM atom_ok;
|
||||
ERL_NIF_TERM atom_error;
|
||||
ERL_NIF_TERM atom_null;
|
||||
ERL_NIF_TERM atom_true;
|
||||
ERL_NIF_TERM atom_false;
|
||||
ERL_NIF_TERM atom_bignum;
|
||||
ERL_NIF_TERM atom_bignum_e;
|
||||
ERL_NIF_TERM atom_bigdbl;
|
||||
ERL_NIF_TERM atom_partial;
|
||||
ERL_NIF_TERM atom_uescape;
|
||||
ERL_NIF_TERM atom_pretty;
|
||||
ERL_NIF_TERM atom_force_utf8;
|
||||
|
||||
ERL_NIF_TERM ref_object;
|
||||
ERL_NIF_TERM ref_array;
|
||||
} emqttd_plugin_mysql_app_st;
|
||||
|
||||
ERL_NIF_TERM make_atom(ErlNifEnv* env, const char* name);
|
||||
ERL_NIF_TERM make_ok(emqttd_plugin_mysql_app_st* st, ErlNifEnv* env, ERL_NIF_TERM data);
|
||||
ERL_NIF_TERM make_error(emqttd_plugin_mysql_app_st* st, ErlNifEnv* env, const char* error);
|
||||
|
||||
ERL_NIF_TERM pbkdf2_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[]);
|
||||
|
||||
int int_from_hex(const unsigned char* p);
|
||||
int int_to_hex(int val, char* p);
|
||||
int utf8_len(int c);
|
||||
int utf8_esc_len(int c);
|
||||
int utf8_validate(unsigned char* data, size_t size);
|
||||
int utf8_to_unicode(unsigned char* buf, size_t size);
|
||||
int unicode_to_utf8(int c, unsigned char* buf);
|
||||
int unicode_from_pair(int hi, int lo);
|
||||
int unicode_uescape(int c, char* buf);
|
||||
int double_to_shortest(char *buf, size_t size, size_t* len, double val);
|
||||
|
||||
#endif // Included EMQTTD_PLUGIN_MYSQL_APP_H
|
|
@ -0,0 +1,278 @@
|
|||
/*
|
||||
* Copyright (c) 2013 Jan-Piet Mens <jpmens()gmail.com>
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions are met:
|
||||
*
|
||||
* 1. Redistributions of source code must retain the above copyright notice,
|
||||
* this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
* 3. Neither the name of mosquitto nor the names of its
|
||||
* contributors may be used to endorse or promote products derived from
|
||||
* this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
||||
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
|
||||
* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
|
||||
* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
|
||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
|
||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
|
||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
|
||||
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
#include <openssl/evp.h>
|
||||
#include <openssl/rand.h>
|
||||
#include "base64.h"
|
||||
#include "erl_nif.h"
|
||||
#include "emqttd_plugin_mysql_app.h"
|
||||
|
||||
#define KEY_LENGTH 24
|
||||
#define SEPARATOR "$"
|
||||
#define SEPARATOR1 "_"
|
||||
#define TRUE (1)
|
||||
#define FALSE (0)
|
||||
|
||||
/*
|
||||
* Split PBKDF2$... string into their components. The caller must free()
|
||||
* the strings.
|
||||
*/
|
||||
|
||||
static int detoken(char *pbkstr, char **sha, int *iter, char **salt, char **key)
|
||||
{
|
||||
char *p, *s, *save;
|
||||
int rc = 1;
|
||||
|
||||
save = s = strdup(pbkstr);
|
||||
|
||||
if ((p = strsep(&s, SEPARATOR1)) == NULL)
|
||||
goto out;
|
||||
if (strcmp(p, "pbkdf2") != 0)
|
||||
goto out;
|
||||
|
||||
if ((p = strsep(&s, SEPARATOR)) == NULL)
|
||||
goto out;
|
||||
*sha = strdup(p);
|
||||
|
||||
if ((p = strsep(&s, SEPARATOR)) == NULL)
|
||||
goto out;
|
||||
*iter = atoi(p);
|
||||
|
||||
if ((p = strsep(&s, SEPARATOR)) == NULL)
|
||||
goto out;
|
||||
*salt = strdup(p);
|
||||
|
||||
if ((p = strsep(&s, SEPARATOR)) == NULL)
|
||||
goto out;
|
||||
*key = strdup(p);
|
||||
|
||||
rc = 0;
|
||||
|
||||
out:
|
||||
free(save);
|
||||
return rc;
|
||||
}
|
||||
|
||||
ERL_NIF_TERM
|
||||
pbkdf2_check(ErlNifEnv* env, int argc, const ERL_NIF_TERM argv[])
|
||||
{
|
||||
ERL_NIF_TERM ret;
|
||||
ErlNifBinary binps, binhash;
|
||||
emqttd_plugin_mysql_app_st* st = enif_alloc(sizeof(emqttd_plugin_mysql_app_st));
|
||||
if(st == NULL) {
|
||||
return make_atom(env, "alloc_error");
|
||||
}
|
||||
|
||||
st->atom_ok = make_atom(env, "ok");
|
||||
st->atom_error = make_atom(env, "error");
|
||||
st->atom_null = make_atom(env, "null");
|
||||
st->atom_true = make_atom(env, "true");
|
||||
st->atom_false = make_atom(env, "false");
|
||||
st->atom_bignum = make_atom(env, "bignum");
|
||||
st->atom_bignum_e = make_atom(env, "bignum_e");
|
||||
st->atom_bigdbl = make_atom(env, "bigdbl");
|
||||
st->atom_partial = make_atom(env, "partial");
|
||||
st->atom_uescape = make_atom(env, "uescape");
|
||||
st->atom_pretty = make_atom(env, "pretty");
|
||||
st->atom_force_utf8 = make_atom(env, "force_utf8");
|
||||
|
||||
// Markers used in encoding
|
||||
st->ref_object = make_atom(env, "$object_ref$");
|
||||
st->ref_array = make_atom(env, "$array_ref$");
|
||||
|
||||
if(argc != 2) {
|
||||
return make_error(st, env, "Bad args");
|
||||
} else if(!enif_inspect_binary(env, argv[0], &binps)|!enif_inspect_binary(env, argv[1], &binhash)) {
|
||||
return make_error(st, env, "Bad args password or username inspect error");
|
||||
}
|
||||
|
||||
char* password = (char*)binps.data;
|
||||
char* hash = (char*)binhash.data;
|
||||
static char *sha, *salt, *h_pw;
|
||||
int iterations, saltlen, blen;
|
||||
char *b64, *keybuf;
|
||||
unsigned char *out;
|
||||
int match = FALSE;
|
||||
const EVP_MD *evpmd;
|
||||
int keylen, rc;
|
||||
|
||||
if (detoken(hash, &sha, &iterations, &salt, &h_pw) != 0)
|
||||
return match;
|
||||
|
||||
/* Determine key length by decoding base64 */
|
||||
if ((keybuf = malloc(strlen(h_pw) + 1)) == NULL) {
|
||||
return make_error(st, env, "internal_error: Out Of memory");
|
||||
}
|
||||
keylen = base64_decode(h_pw, keybuf);
|
||||
if (keylen < 1) {
|
||||
free(keybuf);
|
||||
return make_atom(env, "false");
|
||||
}
|
||||
free(keybuf);
|
||||
|
||||
if ((out = malloc(keylen)) == NULL) {
|
||||
return make_error(st, env, "Cannot allocate out; out of memory\n");
|
||||
}
|
||||
|
||||
#ifdef PWDEBUG
|
||||
fprintf(stderr, "sha =[%s]\n", sha);
|
||||
fprintf(stderr, "iterations =%d\n", iterations);
|
||||
fprintf(stderr, "salt =[%s]\n", salt);
|
||||
fprintf(stderr, "h_pw =[%s]\n", h_pw);
|
||||
fprintf(stderr, "kenlen =[%d]\n", keylen);
|
||||
#endif
|
||||
|
||||
saltlen = strlen((char *)salt);
|
||||
|
||||
evpmd = EVP_sha256();
|
||||
if (strcmp(sha, "sha1") == 0) {
|
||||
evpmd = EVP_sha1();
|
||||
} else if (strcmp(sha, "sha512") == 0) {
|
||||
evpmd = EVP_sha512();
|
||||
}
|
||||
|
||||
rc = PKCS5_PBKDF2_HMAC(password, strlen(password),
|
||||
(unsigned char *)salt, saltlen,
|
||||
iterations,
|
||||
evpmd, keylen, out);
|
||||
if (rc != 1) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
blen = base64_encode(out, keylen, &b64);
|
||||
if (blen > 0) {
|
||||
int i, diff = 0, hlen = strlen(h_pw);
|
||||
#ifdef PWDEBUG
|
||||
fprintf(stderr, "HMAC b64 =[%s]\n", b64);
|
||||
#endif
|
||||
|
||||
/* "manual" strcmp() to ensure constant time */
|
||||
for (i = 0; (i < blen) && (i < hlen); i++) {
|
||||
diff |= h_pw[i] ^ b64[i];
|
||||
}
|
||||
|
||||
match = diff == 0;
|
||||
if (hlen != blen)
|
||||
match = 0;
|
||||
|
||||
free(b64);
|
||||
}
|
||||
|
||||
out:
|
||||
free(sha);
|
||||
free(salt);
|
||||
free(h_pw);
|
||||
free(out);
|
||||
|
||||
if(match == 0){
|
||||
ret = make_atom(env, "false");
|
||||
}else{
|
||||
ret = make_atom(env, "true");
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int pbkdf2_check_native(char *password, char *hash)
|
||||
{
|
||||
static char *sha, *salt, *h_pw;
|
||||
int iterations, saltlen, blen;
|
||||
char *b64;
|
||||
unsigned char key[128];
|
||||
int match = FALSE;
|
||||
const EVP_MD *evpmd;
|
||||
|
||||
if (detoken(hash, &sha, &iterations, &salt, &h_pw) != 0)
|
||||
return match;
|
||||
|
||||
#ifdef PWDEBUG
|
||||
fprintf(stderr, "sha =[%s]\n", sha);
|
||||
fprintf(stderr, "iterations =%d\n", iterations);
|
||||
fprintf(stderr, "salt =[%s]\n", salt);
|
||||
fprintf(stderr, "h_pw =[%s]\n", h_pw);
|
||||
#endif
|
||||
|
||||
saltlen = strlen((char *)salt);
|
||||
|
||||
evpmd = EVP_sha256();
|
||||
if (strcmp(sha, "sha1") == 0) {
|
||||
evpmd = EVP_sha1();
|
||||
} else if (strcmp(sha, "sha512") == 0) {
|
||||
evpmd = EVP_sha512();
|
||||
}
|
||||
|
||||
PKCS5_PBKDF2_HMAC(password, strlen(password),
|
||||
(unsigned char *)salt, saltlen,
|
||||
iterations,
|
||||
evpmd, KEY_LENGTH, key);
|
||||
|
||||
blen = base64_encode(key, KEY_LENGTH, &b64);
|
||||
if (blen > 0) {
|
||||
int i, diff = 0, hlen = strlen(h_pw);
|
||||
#ifdef PWDEBUG
|
||||
fprintf(stderr, "HMAC b64 =[%s]\n", b64);
|
||||
#endif
|
||||
|
||||
/* "manual" strcmp() to ensure constant time */
|
||||
for (i = 0; (i < blen) && (i < hlen); i++) {
|
||||
diff |= h_pw[i] ^ b64[i];
|
||||
}
|
||||
|
||||
match = diff == 0;
|
||||
if (hlen != blen)
|
||||
match = 0;
|
||||
|
||||
free(b64);
|
||||
}
|
||||
|
||||
free(sha);
|
||||
free(salt);
|
||||
free(h_pw);
|
||||
|
||||
return match;
|
||||
}
|
||||
int main()
|
||||
{
|
||||
// char password[] = "hello";
|
||||
// char PB1[] = "PBKDF2$sha256$10000$eytf9sEo8EprP9P3$2eO6tROHiqI3bm+gg+vpmWooWMpz1zji";
|
||||
char password[] = "supersecret";
|
||||
//char PB1[] = "PBKDF2$sha256$10000$YEbSTt8FaMRDq/ib$Kt97+sMCYg00mqMOBAYinqZlnxX8HqHk";
|
||||
char PB1[] = "pbkdf2_sha256$10000$YEbSTt8FaMRDq/ib$Kt97+sMCYg00mqMOBAYinqZlnxX8HqHk";
|
||||
// char PB1[] = "PBKDF2$sha1$10000$XWfyPLeC9gsD6SbI$HOnjU4Ux7RpeBHdqYxpIGH1R5qCCtNA1";
|
||||
// char PB1[] = "PBKDF2$sha512$10000$v/aaCgBZ+VZN5L8n$BpgjSTyb4weVxr9cA2mvQ+jaCyaAPeYe";
|
||||
int match;
|
||||
|
||||
printf("Checking password [%s] for %s\n", password, PB1);
|
||||
|
||||
match = pbkdf2_check_native(password, PB1);
|
||||
printf("match == %d\n", match);
|
||||
return match;
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
// This file is part of Jiffy released under the MIT license.
|
||||
// See the LICENSE file for more information.
|
||||
|
||||
#include "emqttd_plugin_mysql_app.h"
|
||||
|
||||
ERL_NIF_TERM
|
||||
make_atom(ErlNifEnv* env, const char* name)
|
||||
{
|
||||
ERL_NIF_TERM ret;
|
||||
if(enif_make_existing_atom(env, name, &ret, ERL_NIF_LATIN1)) {
|
||||
return ret;
|
||||
}
|
||||
return enif_make_atom(env, name);
|
||||
}
|
||||
|
||||
ERL_NIF_TERM
|
||||
make_ok(emqttd_plugin_mysql_app_st* st, ErlNifEnv* env, ERL_NIF_TERM value)
|
||||
{
|
||||
return enif_make_tuple2(env, st->atom_ok, value);
|
||||
}
|
||||
|
||||
ERL_NIF_TERM
|
||||
make_error(emqttd_plugin_mysql_app_st* st, ErlNifEnv* env, const char* error)
|
||||
{
|
||||
return enif_make_tuple2(env, st->atom_error, make_atom(env, error));
|
||||
}
|
|
@ -0,0 +1,23 @@
|
|||
[
|
||||
{emysql, [
|
||||
{pool, 4},
|
||||
{host, "localhost"},
|
||||
{port, 3306},
|
||||
{username, "root"},
|
||||
{password, "root"},
|
||||
{database, "emqtt"},
|
||||
{encoding, utf8}
|
||||
]},
|
||||
{emqttd_plugin_mysql, [
|
||||
{users_table, auth_user},
|
||||
{acls_table, auth_acl},
|
||||
{field_mapper, [
|
||||
{username, username},
|
||||
{password, password, pbkdf2},
|
||||
{user_super, is_super_user},
|
||||
{acl_username, username},
|
||||
{acl_rw, rw},
|
||||
{acl_topic, topic}
|
||||
]}
|
||||
]}
|
||||
].
|
|
@ -0,0 +1,23 @@
|
|||
[
|
||||
{emysql, [
|
||||
{pool, 4},
|
||||
{host, "59.188.253.198"},
|
||||
{port, 3306},
|
||||
{username, "root"},
|
||||
{password, "lhroot."},
|
||||
{database, "musicfield"},
|
||||
{encoding, utf8}
|
||||
]},
|
||||
{emqttd_plugin_mysql, [
|
||||
{users_table, auth_user},
|
||||
{acls_table, auth_acl},
|
||||
{field_mapper, [
|
||||
{username, username},
|
||||
{password, password, pbkdf2},
|
||||
{user_super, is_super_user},
|
||||
{acl_username, username},
|
||||
{acl_rw, rw},
|
||||
{acl_topic, topic}
|
||||
]}
|
||||
]}
|
||||
].
|
|
@ -0,0 +1,112 @@
|
|||
%%------------------------------------------------------------------------------
|
||||
%% Copyright (c) 2012-2015, Feng Lee <feng@emqtt.io>
|
||||
%%
|
||||
%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%% of this software and associated documentation files (the "Software"), to deal
|
||||
%% in the Software without restriction, including without limitation the rights
|
||||
%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%% copies of the Software, and to permit persons to whom the Software is
|
||||
%% furnished to do so, subject to the following conditions:
|
||||
%%
|
||||
%% The above copyright notice and this permission notice shall be included in all
|
||||
%% copies or substantial portions of the Software.
|
||||
%%
|
||||
%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%% SOFTWARE.
|
||||
%%------------------------------------------------------------------------------
|
||||
%%% @doc
|
||||
%%% MQTT Broker Header.
|
||||
%%%
|
||||
%%% @end
|
||||
%%%-----------------------------------------------------------------------------
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% Banner
|
||||
%%------------------------------------------------------------------------------
|
||||
-define(COPYRIGHT, "Copyright (C) 2012-2015, Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-define(LICENSE_MESSAGE, "Licensed under MIT").
|
||||
|
||||
-define(PROTOCOL_VERSION, "MQTT/3.1.1").
|
||||
|
||||
-define(ERTS_MINIMUM, "6.0").
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% PubSub
|
||||
%%------------------------------------------------------------------------------
|
||||
-type pubsub() :: publish | subscribe.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% MQTT Topic
|
||||
%%------------------------------------------------------------------------------
|
||||
-record(mqtt_topic, {
|
||||
topic :: binary(),
|
||||
node :: node()
|
||||
}).
|
||||
|
||||
-type mqtt_topic() :: #mqtt_topic{}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% MQTT Subscriber
|
||||
%%------------------------------------------------------------------------------
|
||||
-record(mqtt_subscriber, {
|
||||
topic :: binary(),
|
||||
qos = 0 :: 0 | 1 | 2,
|
||||
pid :: pid()
|
||||
}).
|
||||
|
||||
-type mqtt_subscriber() :: #mqtt_subscriber{}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% P2P Queue Subscriber
|
||||
%%------------------------------------------------------------------------------
|
||||
-record(mqtt_queue, {
|
||||
name :: binary(),
|
||||
subpid :: pid(),
|
||||
qos = 0 :: 0 | 1 | 2
|
||||
}).
|
||||
|
||||
-type mqtt_queue() :: #mqtt_queue{}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% MQTT Client
|
||||
%%------------------------------------------------------------------------------
|
||||
-record(mqtt_client, {
|
||||
clientid :: binary(),
|
||||
username :: binary() | undefined,
|
||||
ipaddr :: inet:ip_address()
|
||||
}).
|
||||
|
||||
-type mqtt_client() :: #mqtt_client{}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% MQTT Session
|
||||
%%------------------------------------------------------------------------------
|
||||
-record(mqtt_session, {
|
||||
clientid,
|
||||
session_pid,
|
||||
subscriptions = [],
|
||||
awaiting_ack,
|
||||
awaiting_rel
|
||||
}).
|
||||
|
||||
-type mqtt_session() :: #mqtt_session{}.
|
||||
|
||||
%%------------------------------------------------------------------------------
|
||||
%% MQTT Plugin
|
||||
%%------------------------------------------------------------------------------
|
||||
-record(mqtt_plugin, {
|
||||
name,
|
||||
version,
|
||||
attrs,
|
||||
description
|
||||
}).
|
||||
|
||||
-type mqtt_plugin() :: #mqtt_plugin{}.
|
||||
|
||||
|
Binary file not shown.
|
@ -0,0 +1,32 @@
|
|||
{port_specs, [
|
||||
{"priv/emqttd_plugin_mysql_app.so", [
|
||||
"c_src/*.c"
|
||||
]}
|
||||
]}.
|
||||
|
||||
{port_env, [
|
||||
{".*", "CXXFLAGS", "$CXXFLAGS -g -Wall -Werror -O3"},
|
||||
|
||||
{"(linux|solaris|freebsd|netbsd|openbsd|dragonfly|darwin)",
|
||||
"LDFLAGS", "$LDFLAGS -lstdc++ -lcrypto"},
|
||||
|
||||
%% OS X Leopard flags for 64-bit
|
||||
{"darwin9.*-64$", "CXXFLAGS", "-m64"},
|
||||
{"darwin9.*-64$", "LDFLAGS", "-arch x86_64"},
|
||||
|
||||
%% OS X Snow Leopard flags for 32-bit
|
||||
{"darwin10.*-32$", "CXXFLAGS", "-m32"},
|
||||
{"darwin10.*-32$", "LDFLAGS", "-arch i386"},
|
||||
|
||||
%% This will merge into basho/rebar/rebar.config eventually
|
||||
{"win32", "CFLAGS", "/Wall /DWIN32 /D_WINDOWS /D_WIN32 /DWINDOWS"},
|
||||
{"win32", "CXXFLAGS", "-g -Wall -O3"}
|
||||
]}.
|
||||
|
||||
|
||||
{eunit_opts, [
|
||||
verbose,
|
||||
{report, {
|
||||
eunit_surefire, [{dir,"."}]
|
||||
}}
|
||||
]}.
|
|
@ -0,0 +1,70 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% @Copyright (C) 2012-2015, Feng Lee <feng@emqtt.io>
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc
|
||||
%%% emqttd demo acl module.
|
||||
%%%
|
||||
%%% @end
|
||||
%%%-----------------------------------------------------------------------------
|
||||
-module(emqttd_acl_mysql).
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
-behaviour(emqttd_acl_mod).
|
||||
|
||||
%% ACL callbacks
|
||||
-export([init/1, check_acl/2, reload_acl/1, description/0]).
|
||||
-record(state, {user_table, acl_table, acl_username_field, acl_topic_field, acl_rw_field, user_name_field, user_super_field}).
|
||||
|
||||
init(Opts) ->
|
||||
Mapper = proplists:get_value(field_mapper, Opts),
|
||||
State =
|
||||
#state{
|
||||
user_table = proplists:get_value(users_table, Opts, auth_user),
|
||||
user_super_field = proplists:get_value(is_super, Mapper, is_superuser),
|
||||
user_name_field = proplists:get_value(username, Mapper, username),
|
||||
acl_table = proplists:get_value(acls_table, Opts, auth_acl),
|
||||
acl_username_field = proplists:get_value(acl_username, Mapper, username),
|
||||
acl_rw_field = proplists:get_value(acl_rw, Mapper, rw),
|
||||
acl_topic_field = proplists:get_value(acl_topic, Mapper, topic)
|
||||
},
|
||||
{ok, State}.
|
||||
|
||||
check_acl({#mqtt_client{username = Username}, PubSub, Topic}, #state{user_table = UserTab, acl_table = AclTab, user_name_field = UsernameField, user_super_field = SuperField, acl_topic_field = TopicField, acl_username_field = AclUserField, acl_rw_field = AclRwField}) ->
|
||||
Flag = case PubSub of publish -> 2; subscribe -> 1; pubsub -> 2 end,
|
||||
Where = {'and', {'>=', AclRwField, Flag}, {TopicField, Topic}},
|
||||
Where1 = {'or', {AclUserField, Username}, {AclUserField, "*"}},
|
||||
Where2 = {'and', Where, Where1},
|
||||
case emysql:select(UserTab, {'and', {UsernameField, Username}, {SuperField, 1}}) of
|
||||
{ok, []} ->
|
||||
case emysql:select(UserTab, {UsernameField, Username}) of
|
||||
{ok, []} -> ignore;
|
||||
{ok, _} -> case emysql:select(AclTab, Where2) of
|
||||
{ok, []} -> deny;
|
||||
{ok, _Record} -> allow
|
||||
end
|
||||
end;
|
||||
{ok, _} -> allow
|
||||
end.
|
||||
|
||||
reload_acl(_State) -> ok.
|
||||
|
||||
description() -> "ACL Module by Mysql".
|
|
@ -0,0 +1,110 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc
|
||||
%%% emqttd authentication by mysql 'user' table.
|
||||
%%%
|
||||
%%% @end
|
||||
%%%-----------------------------------------------------------------------------
|
||||
-module(emqttd_auth_mysql).
|
||||
|
||||
-author("Feng Lee <feng@emqtt.io>").
|
||||
|
||||
-include("emqttd.hrl").
|
||||
|
||||
-behaviour(emqttd_auth_mod).
|
||||
|
||||
-export([init/1, check/3, description/0]).
|
||||
|
||||
-define(NOT_LOADED, not_loaded(?LINE)).
|
||||
|
||||
-record(state, {user_table, name_field, pass_field, pass_hash}).
|
||||
|
||||
init(Opts) ->
|
||||
Mapper = proplists:get_value(field_mapper, Opts),
|
||||
{ok, #state{user_table = proplists:get_value(user_table, Opts, auth_user),
|
||||
name_field = proplists:get_value(username, Mapper),
|
||||
pass_field = proplists:get_value(password, Mapper),
|
||||
pass_hash = proplists:get_value(Opts, password_hash)}}.
|
||||
|
||||
check(#mqtt_client{username = undefined}, _Password, _State) ->
|
||||
{error, "Username undefined"};
|
||||
check(_Client, undefined, _State) ->
|
||||
{error, "Password undefined"};
|
||||
check(#mqtt_client{username = Username}, Password,
|
||||
#state{user_table = UserTab, pass_hash = Type,
|
||||
name_field = NameField, pass_field = PassField}) ->
|
||||
Where = {'and', {NameField, Username}, {PassField, hash(Type, Password)}},
|
||||
if Type =:= pbkdf2 ->
|
||||
case emysql:select(UserTab, [PassField], {NameField, Username}) of
|
||||
{ok, []} -> {error, "User not exist"};
|
||||
{ok, Records} ->
|
||||
if length(Records) =:= 1 ->
|
||||
case pbkdf2_check(Password, lists:nth(Records, 1)) of
|
||||
true ->
|
||||
{ok, []};
|
||||
false ->
|
||||
{error, "UserName or Password is invalid"};
|
||||
ErrorInfo ->
|
||||
{error, ErrorInfo}
|
||||
end;
|
||||
true ->
|
||||
{error, "UserName is ambiguous"}
|
||||
end
|
||||
end;
|
||||
true ->
|
||||
case emysql:select(UserTab, Where) of
|
||||
{ok, []} -> {error, "Username or Password "};
|
||||
{ok, _Record} -> ok
|
||||
end
|
||||
end.
|
||||
|
||||
description() -> "Authentication by MySQL".
|
||||
|
||||
hash(plain, Password) ->
|
||||
Password;
|
||||
|
||||
hash(md5, Password) ->
|
||||
hexstring(crypto:hash(md5, Password));
|
||||
|
||||
hash(sha, Password) ->
|
||||
hexstring(crypto:hash(sha, Password)).
|
||||
|
||||
hexstring(<<X:128/big-unsigned-integer>>) ->
|
||||
lists:flatten(io_lib:format("~32.16.0b", [X]));
|
||||
|
||||
hexstring(<<X:160/big-unsigned-integer>>) ->
|
||||
lists:flatten(io_lib:format("~40.16.0b", [X])).
|
||||
|
||||
not_loaded(Line) ->
|
||||
erlang:nif_error({not_loaded, [{module, ?MODULE}, {line, Line}]}).
|
||||
|
||||
pbkdf2_check(Password, Pbkstr) ->
|
||||
case nif_pbkdf2_check(Password, Pbkstr) of
|
||||
{error, _} = Error ->
|
||||
throw(Error);
|
||||
IOData ->
|
||||
IOData
|
||||
end.
|
||||
|
||||
nif_pbkdf2_check(Password, Pbkstr) ->
|
||||
?NOT_LOADED.
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
{application, emqttd_plugin_mysql,
|
||||
[
|
||||
{description, "emqttd MySQL Authentication Plugin"},
|
||||
{vsn, "1.0"},
|
||||
{registered, []},
|
||||
{applications, [
|
||||
kernel,
|
||||
stdlib
|
||||
]},
|
||||
{mod, {emqttd_plugin_mysql_app, []}},
|
||||
{env, []}
|
||||
]}.
|
|
@ -0,0 +1,80 @@
|
|||
%%%-----------------------------------------------------------------------------
|
||||
%%% Copyright (c) 2012-2015 eMQTT.IO, All Rights Reserved.
|
||||
%%%
|
||||
%%% Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
%%% of this software and associated documentation files (the "Software"), to deal
|
||||
%%% in the Software without restriction, including without limitation the rights
|
||||
%%% to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
%%% copies of the Software, and to permit persons to whom the Software is
|
||||
%%% furnished to do so, subject to the following conditions:
|
||||
%%%
|
||||
%%% The above copyright notice and this permission notice shall be included in all
|
||||
%%% copies or substantial portions of the Software.
|
||||
%%%
|
||||
%%% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
%%% IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
%%% FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
%%% AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
%%% LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
%%% OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
||||
%%% SOFTWARE.
|
||||
%%%-----------------------------------------------------------------------------
|
||||
%%% @doc
|
||||
%%% emqttd mysql authentication app.
|
||||
%%%
|
||||
%%% @end
|
||||
%%%-----------------------------------------------------------------------------
|
||||
-module(emqttd_plugin_mysql_app).
|
||||
-on_load(init/0).
|
||||
-behaviour(application).
|
||||
%% Application callbacks
|
||||
-export([start/2, prep_stop/1, stop/1, nif_pbkdf2_check/2]).
|
||||
|
||||
-behaviour(supervisor).
|
||||
%% Supervisor callbacks
|
||||
-export([init/1]).
|
||||
-define(NOT_LOADED, not_loaded(?LINE)).
|
||||
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Application callbacks
|
||||
%%%=============================================================================
|
||||
|
||||
start(_StartType, _StartArgs) ->
|
||||
Env = application:get_all_env(),
|
||||
emqttd_access_control:register_mod(auth, emqttd_auth_mysql, Env),
|
||||
emqttd_access_control:register_mod(acl, emqttd_acl_mysql, Env),
|
||||
crypto:start(),
|
||||
supervisor:start_link({local, ?MODULE}, ?MODULE, []).
|
||||
|
||||
prep_stop(State) ->
|
||||
emqttd_access_control:unregister_mod(auth, emqttd_auth_mysql), State,
|
||||
emqttd_access_control:unregister_mod(acl, emqttd_acl_mysql), State,
|
||||
crypto:stop().
|
||||
|
||||
stop(_State) ->
|
||||
ok.
|
||||
|
||||
init() ->
|
||||
PrivDir = case code:priv_dir(?MODULE) of
|
||||
{error, _} ->
|
||||
EbinDir = filename:dirname(code:which(?MODULE)),
|
||||
AppPath = filename:dirname(EbinDir),
|
||||
filename:join(AppPath, "priv");
|
||||
Path ->
|
||||
Path
|
||||
end,
|
||||
erlang:load_nif(filename:join(PrivDir, "emqttd_plugin_mysql_app"), 0).
|
||||
|
||||
%%%=============================================================================
|
||||
%%% Supervisor callbacks(Dummy)
|
||||
%%%=============================================================================
|
||||
|
||||
init([]) ->
|
||||
{ok, {{one_for_one, 5, 10}, []}}.
|
||||
|
||||
not_loaded(Line) ->
|
||||
erlang:nif_error({not_loaded, [{module, ?MODULE}, {line, Line}]}).
|
||||
|
||||
nif_pbkdf2_check(Password, Hash) ->
|
||||
?NOT_LOADED.
|
|
@ -384,9 +384,15 @@ encode_where({like, Field, Value}) ->
|
|||
encode_where({'<', Field, Value}) ->
|
||||
atom_to_list(Field) ++ " < " ++ encode(Value);
|
||||
|
||||
encode_where({'<=', Field, Value}) ->
|
||||
atom_to_list(Field) ++ " <= " ++ encode(Value);
|
||||
|
||||
encode_where({'>', Field, Value}) ->
|
||||
atom_to_list(Field) ++ " > " ++ encode(Value);
|
||||
|
||||
encode_where({'>=', Field, Value}) ->
|
||||
atom_to_list(Field) ++ " >= " ++ encode(Value);
|
||||
|
||||
encode_where({'in', Field, Values}) ->
|
||||
InStr = string:join([encode(Value) || Value <- Values], ","),
|
||||
atom_to_list(Field) ++ " in (" ++ InStr ++ ")";
|
||||
|
|
Loading…
Reference in New Issue