Git Product home page Git Product logo

emqx-auth-http's Introduction

emqx_auth_http

EMQX HTTP Auth/ACL Plugin

Build

make && make tests

Configure the Plugin

File: etc/emqx_auth_http.conf

##--------------------------------------------------------------------
## Authentication request.
##
## Variables:
##  - %u: username
##  - %c: clientid
##  - %a: ipaddress
##  - %r: protocol
##  - %P: password
##  - %C: common name of client TLS cert
##  - %d: subject of client TLS cert
##
## Value: URL
auth.http.auth_req = http://127.0.0.1:8080/mqtt/auth
## Value: post | get | put
auth.http.auth_req.method = post
## Value: Params
auth.http.auth_req.params = clientid=%c,username=%u,password=%P

##--------------------------------------------------------------------
## Superuser request.
##
## Variables:
##  - %u: username
##  - %c: clientid
##  - %a: ipaddress
##  - %r: protocol
##  - %P: password
##  - %C: common name of client TLS cert
##  - %d: subject of client TLS cert
##
## Value: URL
auth.http.super_req = http://127.0.0.1:8080/mqtt/superuser
## Value: post | get | put
auth.http.super_req.method = post
## Value: Params
auth.http.super_req.params = clientid=%c,username=%u

##--------------------------------------------------------------------
## ACL request.
##
## Variables:
##  - %A: 1 | 2, 1 = sub, 2 = pub
##  - %u: username
##  - %c: clientid
##  - %a: ipaddress
##  - %r: protocol
##  - %m: mountpoint
##  - %t: topic
##
## Value: URL
auth.http.acl_req = http://127.0.0.1:8080/mqtt/acl
## Value: post | get | put
auth.http.acl_req.method = get
## Value: Params
auth.http.acl_req.params = access=%A,username=%u,clientid=%c,ipaddr=%a,topic=%t

Load the Plugin

./bin/emqx_ctl plugins load emqx_auth_http

HTTP API

200 if ok

4xx if unauthorized

License

Apache License Version 2.0

Author

EMQX Team.

emqx-auth-http's People

Contributors

emqplus avatar gbrehmer avatar gilbertwong96 avatar hjianbo avatar huangdan avatar k32 avatar lautarojayat avatar rory-z avatar spring2maz avatar terry-xiaoyu avatar tigercl avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

emqx-auth-http's Issues

Password param for ACL and superuser requests

From documentation one can understand that "%P: password" is passed also for ACL and superuser requests. In reality password is passed only for auth request.
Is it a bug or just wrong documentation?

Is this in support of http2.

This plugin is cool,But I want use http2 to validate my topics.
And I am not familiar with Erlang,So, May you help me with that.

Not sending auth request

I am using emqx docker v3.1. I tried and config http auth plugin from dashboard plugin. I set every endpoint to some url from my host machine. But no request received and every attempt to connect to server fails. Ofcource if I disable plugin everthing works fine.
I even tried wget from container and it went through.
my config file look like this


##--------------------------------------------------------------------
## HTTP Auth/ACL Plugin
##--------------------------------------------------------------------

##--------------------------------------------------------------------
## Authentication request.
##
## Variables:
##  - %u: username
##  - %c: clientid
##  - %a: ipaddress
##  - %P: password
##  - %cn: common name of client TLS cert
##  - %dn: subject of client TLS cert
##
## Value: URL
auth.http.auth_req = http://10.0.75.1:5000/mqtt/auth
## Value: post | get | put
auth.http.auth_req.method = post
## Value: Params
auth.http.auth_req.params = clientid=%c,username=%u,password=%P

##--------------------------------------------------------------------
## Superuser request.
##
## Variables:
##  - %u: username
##  - %c: clientid
##  - %a: ipaddress
##
## Value: URL
auth.http.super_req = http://10.0.75.1:5000/mqtt/auth
## Value: post | get | put
auth.http.super_req.method = post
## Value: Params
auth.http.super_req.params = clientid=%c,username=%u

##--------------------------------------------------------------------
## ACL request.
##
## Variables:
##  - %A: 1 | 2, 1 = sub, 2 = pub
##  - %u: username
##  - %c: clientid
##  - %a: ipaddress
##  - %t: topic
##
## Value: URL
auth.http.acl_req = http://10.0.75.1:5000/mqtt/auth
## Value: post | get | put
auth.http.acl_req.method = post
## Value: Params
auth.http.acl_req.params = access=%A,username=%u,clientid=%c,ipaddr=%a,topic=%t

Allow auth for clientid only (without username and password)

I would like to have an option to let's the plugin call the http service even if the username and password are empty. We still have clientId and password.

https://github.com/emqtt/emq-auth-http/blob/132a8646a7163ad2913bf158bbc795a95a8744f3/src/emq_auth_http.erl#L35-L36

Adding option like auth.http.auth_req.mandatory_username and auth.http.auth_req.mandatory_password will allow to manage this case.

Adding anonymous access do not save this use case because I still want to validate that the client_id is registered.

auth parameters can use json format data?

now the auth parameters use "&" to Differentiate between different fields ,eg:clientid=123&username=jiangch1&password=jiangch3
but if the passwd field or clientid field contains character “&”,how to Differentiate between different fields?
In my view, auth parameters use json format data is a better way.but I do not know how to get the value of field clientid from parameters.Can the emqx-auth-http use json format data?

Is 'emqx_auth_http.auth_req' required?

I want enable http ACL,but i don't want to enable Authentication,In the doc:

The emqx_auth_http plugin also includes ACL feature, which can be disabled via comments.

But if i comment 'emqx_auth_http.auth_req', the emqx_auth_http plugin cannot start!

Environment variable support

I am trying to use this auth method for my emqtt docker container, but the environment variables are not set correctly

Variables

EMQ_AUTH__HTTP__AUTH_REQ: "http://HTTP_SERVICE:5100/auth/mqtt"
EMQ_AUTH__HTTP__ACL_REQ: "http://HTTP_SERVICE:5100/acl/mqtt"

Error

14:06:40.212 [error] HTTP http://127.0.0.1:8080/mqtt/auth Error: {failed_connect,[{to_address,{"127.0.0.1",8080}},{inet,[inet],econnrefused}]}

emqtt version: 2.1.2

Adding interval between auth requests for same clientId

when mqtt-auth-http returns 4xx, clients try to reconnect every second which creates enormous traffic, is there any way to provide an interval in someway to be able to cache last unauthorized request for some interval so that it doesnt make http request for same clientId every time client tries to connect?

emq-auth-http plugin does not try to communicate with specified server and always return false when enabling it

Hi there,

Here is my situation, I have ran up three dockers, auth_server, emqtt_server, and a client.

auth_server is written by nodejs, and always return 200 when receiving any http request.

client connect the emqtt server using eclipse paho project, and I have confirmed that client is workable when emqtt unloaded emq-auth-http plugin.

And each server can ping my auth_server, and it's also fine when sending http request with curl.

What I want to do is that my client attempts to connect to emqtt_server and requests to publish a message, and after emqtt_server received the request, emqtt_server will send the authenticate request to auth_server through emq-auth-http plugin. Then, if received 200, allow the client to connect and publish.

According to result, emq-auth-http plugin does not send any http request to my auth_server, and instantly return authenticate fail to client.

Here's my emq_auth_http.conf

##--------------------------------------------------------------------
## HTTP Auth/ACL Plugin
##--------------------------------------------------------------------

## Variables: %u = username, %c = clientid, %a = ipaddress, %P = password, %t = topic

auth.http.auth_req = http://AUTH.SERVER.COM:8080/mqtt/auth
auth.http.auth_req.method = post
auth.http.auth_req.params = clientid=%c,username=%u,password=%P

auth.http.super_req = http://AUTH.SERVER.COM:8080/mqtt/superuser
auth.http.super_req.method = post
auth.http.super_req.params = clientid=%c,username=%u

## 'access' parameter: sub = 1, pub = 2
auth.http.acl_req = http://AUTH.SERVER.COM:8080/mqtt/acl
auth.http.acl_req.method = get
auth.http.acl_req.params = access=%A,username=%u,clientid=%c,ipaddr=%a,topic=%t

auth.http.acl_nomatch = allow

And I have tried to modify my emq_auth_http.conf like #5 but still failed

## Variables: %u = username, %c = clientid, %a = ipaddress, %P = password, %t = topic 

{super_req, [
  {method, post},
  {url, "http://AUTH.SERVER.COM:8080/mqtt/superuser"},
  {params, [
    {username, "%u"},
    {clientid, "%c"}
  ]}
]}.

{auth_req, [
  {method, post},
  {url, "http://AUTH.SERVER.COM:8080/mqtt/auth"},
  {params, [       
    {clientid, "%c"}, 
    {username, "%u"},    
    {password, "%P"}   
  ]}                                 
]}.

## 'access' parameter: sub = 1, pub = 2 
{acl_req, [     
  {method, post},      
  {url, "http://AUTH.SERVER.COM:8080/mqtt/acl"},                   
  {params, [   
    {access,   "%A"},   
    {username, "%u"}, 
    {clientid, "%c"},      
    {ipaddr,   "%a"},     
    {topic,    "%t"}       
  ]}                  
]}.   

Remote auth url is not being called when using HTTP PUBLISH API

Hi,

When emqttd_auth_http plugin loaded, Using of HTTP PUBLISH API always return 401. and as far as I know, it seems like remote auth url is not being called when using HTTP PUBLISH API.

my "emqttd_auth_http.conf" looks like below :

%% Variables: %u = username, %c = clientid, %a = ipaddress, %t = topic

{super_req, [
  {method, post},
  {url, "http://MYDOMAIN.COM:80/mqtt/superuser"},
  {params, [
    {username, "%u"},
    {clientid, "%c"}
  ]}
]}.

{auth_req, [
  {method, post},
  {url, "http://MYDOMAIN.COM:80/mqtt/auth"},
  {params, [
    {clientid, "%c"},
    {username, "%u"},
    {password, "%P"}
  ]}
]}.

%% 'access' parameter: sub = 1, pub = 2

{acl_req, [
  {method, post},
  {url, "http://MYDOMAIN.COM:80/mqtt/acl"},
  {params, [
    {access,   "%A"},
    {username, "%u"},
    {clientid, "%c"},
    {ipaddr,   "%a"},
    {topic,    "%t"}
  ]}
]}.


Sending null instead of undefined

I find that emqx will send things like this:

clientid=mosqsub%2F28265-jiang&username=undefined&password=undefined

if I run:

mosquitto_sub -t test 

This is not really good in other languages which don't have undefined, also in JSON we don't have undefined neither.

Like in rust, it has been deserialized as:

AuthUser { username: Some("undefined"), clientid: Some("mosqsub/29239-jiang"), password: "undefined" }

Can it be replaced by null?

ACL on x509 certs individually based login

I have a device where I have configured x509 certificate to authenticate to emqx using this plugin.

But there is no way to get %C (the CN) from the certificate to ACL (for doing topic based ACL).

Is there any way to ACL on x509 certificate using CN or any unique identifier ?

No ACL request

I setup http server and server can receives auth and super request, but there is no acl request. Is something wrong with the configuration?

thanks.

emqtt version: 2.3.11
emq_auth_http.conf:

auth.http.auth_req = http://127.0.0.1:8090/v1/mqtt/auth
auth.http.auth_req.method = post
auth.http.auth_req.params = clientid=%c,username=%u,password=%P,ipaddr=%a

auth.http.super_req = http://127.0.0.1:8090/v1/mqtt/superuser
auth.http.super_req.method = post
auth.http.super_req.params = clientid=%c,username=%u,ipaddr=%a

auth.http.acl_req = http://127.0.0.1:8090/v1/mqtt/acl
auth.http.acl_req.method = post
auth.http.acl_req.params = access=%A,username=%u,clientid=%c,ipaddr=%a,topic=%t

Is cache available for emqx-auth-http plugin?

Dear there

Is cache available for emqx-auth-http plugin? Similar to the Mosquitto MQTT HTTP auth, a parameter of caching time can be set so that same auth response will be provided for requests within the time period?

emq_auth_http plugin does not check with the auth_server when publishing/subscribing messages

System info:

docker version: 1.12.5
emqtt version: emqttd-docker-v2.0.5
auth_server: running with nodejs http server on another docker
mqtt client: paho-mqtt-javascript

Issue description:
Both emqtt server and auth server are on, and both of them can ping each other.
I am trying to authenticate connection and topic access control with emq_auth_http plugin.

According to the result, emqtt does check the connection with the auth server through emq_auth_http plugin, however, when client tries to publish the message, emqtt server DOES NOT check with the auth server through the plugin and instantly allows the client to publish the message.

Is this a known issue on this plugin, or I need to do other settings to enable ACL through this plugin?

socket_closed_remotely

Hi,

We are testing the plugin to authorize via a local nginx server. In our tests everything works well, except that from time to time we are getting the following error log:

HTTP http://127.0.0.1/auth Error: socket_closed_remotely
Client(): Username '' login failed for socket_closed_remotely

In nginx access/error logs there is no trace. It looks like the request never reached the server, so I suspect this bug emerges from the Erlang. Our machine was tuned according to the "1 million connections" guide on the website.

Any ideas?

ACL endpoint isnt called

The /mqtt/acl won't be called when I publish or subscribe a topic. The other works fine.

##--------------------------------------------------------------------
## HTTP Auth/ACL Plugin
##--------------------------------------------------------------------

## Variables: %u = username, %c = clientid, %a = ipaddress, %P = password, %t = topic

auth.http.auth_req = http://127.0.0.1:3000/mqtt/auth
auth.http.auth_req.method = post
auth.http.auth_req.params = clientid=%c,username=%u,password=%P

auth.http.super_req = http://127.0.0.1:3000/mqtt/superuser
auth.http.super_req.method = post
auth.http.super_req.params = clientid=%c,username=%u

## 'access' parameter: sub = 1, pub = 2
auth.http.acl_req = http://127.0.0.1:3000/mqtt/acl
auth.http.acl_req.method = get
auth.http.acl_req.params = access=%A,username=%u,clientid=%c,ipaddr=%a,topic=%t

auth.http.acl_nomatch = deny

ACL expiration

Once the broker has requested authorization from the http endpoint for a given client-id, it will never request it again until it restarts (losing the state) or the client reconnects by itself. The result is cached for ever. Makes sense, requesting the authorization for every message would be a huge performance hit.

Nonetheless, http provides the "Cache-Control" and "Expires" headers for controlling caching. In a dynamic environment, ACLs can change quite often and it would be cumbersome to restart the broker every time. I suggest this http plugin takes into account these headers. The user could effectively control caching as needed.

Unfortunately I don't write erlang so I can't help.

401 status still let the client to connect

Environment

  • OS: CentOS-7
  • EMQ: v3.2.3

Description

I am returning 401.but the client is still able to connect.

error log:

2019-09-26 17:56:27.748 [warning] [email protected]:20698 [Protocol] Client sdfxvcvxc (Username: 'wang') login failed for 401
2019-09-26 17:56:42.046 [warning] [email protected]:20707 [Protocol] Client sdfxvcvxcsdfsdf (Username: 'wang') login failed for 401

Http ACL auth doesn't work

Hi!
I do all the same that has been written in the documentation. Simple http auth is work fine, but when I try to use http ACL auth - it doesn't work for me, despite the fact that settings are very close. When I try to refer to the broker via Eclipse Paho I get the error with status code 3 that means the broker isn't available. I turned on emqx_auth_http from dashboard. This is my EMQX settings for http ACL auth:
emqx.conf

allow_anonymous = false
listener.tcp.external = 1884

plugins/emqx_auth_http.conf

auth.http.auth_req = http://127.0.0.1:8991/mqtt/auth
auth.http.auth_req.method = post
auth.http.auth_req.params = clientid=%c,username=%u,password=%P

auth.http.super_req = http://somesite.com/mqtt/superuser
auth.http.super_req.method = post
auth.http.super_req.params = clientid=%c,username=%u

auth.http.acl_req = http://somesite/mqtt/acl
auth.http.acl_req.method = post
auth.http.acl_req.params = access=%A,username=%u,clientid=%c,ipaddr=%a,topic=%t,mountpoint=%m

auth.http.request.retry_times = 3
auth.http.request.retry_interval = 1s
auth.http.request.retry_backoff = 2.0

Endpoints(http://somesite.com/mqtt/superuser, http://somesite/mqtt/acl) are working fine and I can get access to it from Postaman app. May be you could tell me where I do something wrong in my configuration or somewhere else?

Is there a way to reload config from the CLI?

OS : centos 7.4
emqx : 3.2.3

Is there a way to reload config from the CLI?

I know it's possible to change settings on the dashboard screen.
but i want CLI reload config
The emqx_ctl command does not seem to reload.

  • "emqx_ctl plugin reload emqx_auth_http"
  • I checked on the dashboard.

can not restart emqx. (Existing sessions need to be kept connected)

Build error: missing ssl_api.hrl

Have Erlang/OTP 22 installed. Cloned the plugin and ran make:
`

make
rebar3 compile
===> Verifying dependencies...
===> Running neotoma...
===> Compiling c_src/decoder.c
===> Compiling c_src/encoder.c
... more ...
===> Compiling emqx_reloader
===> Compiling esockd
===> Compiling _build/default/lib/esockd/src/esockd_transport.erl failed
_build/default/lib/esockd/src/esockd_transport.erl:20: can't find include lib "ssl/src/ssl_api.hrl"
`

Topic scattered on ACL request

Hello,

I've run into an issue. The Plugin seems to mess up the topic name when sending it via a http request.

Here is my emq_auth_http.config:

auth.http.auth_req = https://localhost:3030/auth/mq
auth.http.auth_req.method = post
auth.http.auth_req.params = clientid=%c,username=%u,password=%P

auth.http.super_req = https://localhost:3030/auth/mq/su
auth.http.super_req.method = post
auth.http.super_req.params = clientid=%c,username=%u

auth.http.acl_req = https://localhost:3030/auth/mq/acl
auth.http.acl_req.method = post
auth.http.acl_req.params = access=%A,username=%u,clientid=%c,ipaddr=%a,topic=%t

These are the params the server receives:

{ access: '1',
  username: 'test',
  clientid: 'mqttjs_19ac257e',
  ipaddr: '172.17.0.1',
  topic: '%t##--------------------------------------------------------------------' }
POST /auth/mq/acl 200 1.283 ms - 2

I've used EMQ 2.1.2 and EMQ 2.2, both with the same result.

Or is topic of any special data type I have to parse in a different way?

Best Wishes
Marcel

Authenticate on /mqtt/superuser and /mqtt/acl request?

I using emqx-auth-http request to authenticate with API server. As API server should not use session and required to authenticate with username and password on each API request (Or, using JWT in short time period for security).

In document of emqx-auth-http using username/password on /mqtt/auth request only, while on /mqtt/superuser and /mqtt/acl not documentation about that.

So, I need you confirm that is no authenticate on that both request?, otherwise please you suggest to use authentication with EMQ too.

Thanks.

Possibility to return superuser indication

How is the plugin intended to be used in case the external authentication module has the knowledge of normal users vs superusers?
I see that if the plugin receives a 4xx reply to a super_req, it immediately retries with a auth_req. This means that either the use of super_req is disabled, or the authentication of each normal user will systematically cost two request-response rounds with the external module.
Would it be possible to just use auth_req, and have the indication of whether the user is a superuser or a normal user in the response body?

Auth & Superuser endpoint with json formatted body

It could be more developer friendly if broker send json formatted data in post method rather plain text.
Ex :

{
    "clientid": "mosqsub",
    "username": "sakib",
    "password": "123"
}

or pass them as url param like access endpoint.

connect with TLS but got undefined value of placeholder "%C" and "%d"

Version: EMQ X Broker 4.0.5
Config:

auth.http.auth_req.params = clientid=%c,username=%u,password=%P,commonname=%C,subject=%d,protocol=%r,ipaddress=%a

What i got: (API support by Golang.httpserver)

2020-04-22 13:33:18.133 [Debug] map[clientid:[36CYFTSNHPabc] commonname:[undefined] ipaddress:[127.0.0.1] password:[78b97a6b9b661dec4b94e1473e3cf17902ed85e78fbfc676c66510cf104dcdf9] protocol:[mqtt] subject:[undefined] username:[36CYFTSNHPabc]]

I also find this issue #137 . placeholder changed but param of "maps:get" not. is that problem cause?

and i'm very sure the client is connected with SSL.

image

i want pass http auth to the private ip network

i want no use http auth to the private ip network ( this private ip is administrator ip network.)
However, regular users should check the authentication. (regular users is public ip network)

Is there any way to set this up?

No query params in http requests

I created a nodejs app to service the requests of the http plugin but I'm not get any of the variables in a query string or request body...

Using the latest emqtt deb version server and the config file is correct as the node app gets the request but without any params, what am I doing wrong?

EDIT:

Helps when you have body parser setup correctly in your node app...

Add headers in auth request

The request forwarded by the plugin contains a minimal set of headers.

There should be a way to handle headers to work with picky webservers.
As an example here's a request captured from EMQ and one crafted to support a KeyCloak authentication system.

The EMQ request does not comply with the required Accept header and a 400 response code is received, while a crafted request with such header passes.

EMQ

----- Request Start ----->
/auth/realms/Ingestion/protocol/openid-connect/token
content-type: application/x-www-form-urlencoded
content-length: 117
te: 
host: localhost:8081
connection: keep-alive
client_id=emqtt_ingestion&username=2d24349a-373d-4685-a8e3-2f121e5e666d&password=CSvNsV2sPsAnC55P&grant_type=password
<----- Request End -----

CRAFTED

----- Request Start ----->
/auth/realms/Ingestion/protocol/openid-connect/token
Host: localhost:8081
Content-Length: 117
Accept-Encoding: gzip, deflate
Accept: */*
User-Agent: HTTPie/0.9.4
Connection: keep-alive
Content-Type: application/x-www-form-urlencoded
client_id=emqtt-ingestion&username=2d24349a-373d-4685-a8e3-2f121e5e666d&grant_type=password&password=CSvNsV2sPsAnC55P
<----- Request End -----

ACL校验失效

在ACL校验请求的时候,服务器可以接收到ACL请求,但是不管服务器返回的是200还是4xx,都能通过校验并正常进行主题的订阅及消息的发布
版本:emqttd-windows10-v2.2-beta.3.zip

Disable ACL support

With the new config layout / implementation it is not possible to remove ACL Support by removing corresponding settings. We only need authentication. Plain hardcoded ACL config file is enough (w/o http call)

15:25:27.735 [error] Error generating configuration in phase apply_translations^M
15:25:27.735 [error] Translation for 'emq_auth_http.acl_req' expected to find setting 'auth.http.acl_req.params' but was missing

ACL request payload access field always equal to 2

I am testing emqx with auth http plugin enabled, but my http server always receiving payload with access equal to 2, no matter my client is trying to subscribing a topic or publishing a topic.

ACL config emqx_auth_http.conf goes here:

##--------------------------------------------------------------------
## ACL request.
##
## Variables:
##  - %A: 1 | 2, 1 = sub, 2 = pub
##  - %u: username
##  - %c: clientid
##  - %a: ipaddress
##  - %t: topic
##
## Value: URL
auth.http.acl_req = http://backend:9000/v1/auth/acl
## Value: post | get | put
auth.http.acl_req.method = post
## Value: Params
auth.http.acl_req.params = access=%A,username=%u,clientid=%c,ipaddr=%a,topic=%t

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.