Giter Site home page Giter Site logo

sso's Introduction

jasny-banner

Single Sign-On for PHP

PHP Scrutinizer Code Quality Code Coverage Packagist Stable Version Packagist License

Jasny SSO is a relatively simple and straightforward solution for single sign on (SSO).

With SSO, logging into a single website will authenticate you for all affiliate sites. The sites don't need to share a toplevel domain.

How it works

When using SSO, we can distinguish 3 parties:

  • Client - This is the browser of the visitor
  • Broker - The website which is visited
  • Server - The place that holds the user info and credentials

The broker has an id and a secret. These are known to both the broker and server.

When the client visits the broker, it creates a random token, which is stored in a cookie. The broker will then send the client to the server, passing along the broker's id and token. The server creates a hash using the broker id, broker secret and the token. This hash is used to create a link to the user's session. When the link is created the server redirects the client back to the broker.

The broker can create the same link hash using the token (from the cookie), the broker id and the broker secret. When doing requests, it passes that hash as a session id.

The server will notice that the session id is a link and use the linked session. As such, the broker and client are using the same session. When another broker joins in, it will also use the same session.

For a more in depth explanation, please read this article.

How is this different from OAuth?

With OAuth, you can authenticate a user at an external server and get access to their profile info. However, you aren't sharing a session.

A user logs in to website foo.com using Google OAuth. Next they visit website bar.org which also uses Google OAuth. Regardless of that, they are still required to press the 'login' button on bar.org.

With Jasny SSO both websites use the same session. So when the user visits bar.org, they are automatically logged in. When they log out (on either of the sites), they are logged out for both.

Installation

Install this library through composer

composer require jasny/sso

Demo

There is a demo server and two demo brokers as example. One with normal redirects and one using JSONP / AJAX.

To prove it's working you should setup the server and two or more brokers, each on their own machine and their own (sub)domain. However, you can also run both server and brokers on your own machine, simply to test it out.

On *nix (Linux / Unix / OSX) run:

php -S localhost:8000 -t demo/server/
export SSO_SERVER=http://localhost:8000/attach.php SSO_BROKER_ID=Alice SSO_BROKER_SECRET=8iwzik1bwd; php -S localhost:8001 -t demo/broker/
export SSO_SERVER=http://localhost:8000/attach.php SSO_BROKER_ID=Greg SSO_BROKER_SECRET=7pypoox2pc; php -S localhost:8002 -t demo/broker/
export SSO_SERVER=http://localhost:8000/attach.php SSO_BROKER_ID=Julius SSO_BROKER_SECRET=ceda63kmhp; php -S localhost:8003 -t demo/ajax-broker/

Now open some tabs and visit

username password
jackie jackie123
john john123

Note that after logging in, you need to refresh on the other brokers to see the effect.

Usage

Server

The Server class takes a callback as first constructor argument. This callback should look up the secret for a broker based on the id.

The second argument must be a PSR-16 compatible cache object. It's used to store the link between broker token and client session.

use Jasny\SSO\Server\Server;

$brokers = [
    'foo' => ['secret' => '8OyRi6Ix1x', 'domains' => ['example.com']],
    // ...
];

$server = new Server(
    fn($id) => $brokers[$id] ?? null, // Unique secret and allowed domains for each broker.
    new Cache()                       // Any PSR-16 compatible cache
);

In this example the brokers are simply configured as an array, but typically you want to fetch the broker info from a DB.

Attach

A client needs to attach the broker token to the session id by doing an HTTP request to the server. This request can be handled by calling attach().

The attach() method returns a verification code. This code must be returned to the broker, as it's needed to calculate the checksum.

$verificationCode = $server->attach();

If it's not possible to attach (for instance in case of an incorrect checksum), an Exception is thrown.

Handle broker API request

After the client session is attached to the broker token, the broker is able to send API requests on behalf of the client. Calling the startBrokerSession() method with start the session of the client based on the bearer token. This means that these request the server can access the session information of the client through $_SESSION.

$server->startBrokerSession();

The broker could use this to login, logout, get user information, etc. The API for handling such requests is outside the scope of the project. However since the broker uses normal sessions, any existing the authentication can be used.

If you're lookup for an authentication library, consider using Jasny Auth.

PSR-7

By default, the library works with superglobals like $_GET and $_SERVER. Alternatively it can use a PSR-7 server request. This can be passed to attach() and startBrokerSession() as argument.

$verificationCode = $server->attach($serverRequest);

Session interface

By default, the library uses the superglobal $_SESSION and the php_session_*() functions. It does this through the GlobalSession object, which implements SessionInterface.

For projects that use alternative sessions, it's possible to create a wrapper that implements SessionInterface.

use Jasny\SSO\Server\SessionInterface;

class CustomerSessionHandler implements SessionInterface
{
    // ...
}

The withSession() methods creates a copy of the Server object with the custom session interface.

$server = (new Server($callback, $cache))
    ->withSession(new CustomerSessionHandler());

The withSession() method can also be used with a mock object for testing.

Logging

Enable logging for debugging and catching issues.

$server = (new Server($callback, $cache))
    ->withLogging(new Logger());

Any PSR-3 compatible logger can be used, like Monolog or Loggy. The context may contain the broker id, token, and session id.

Broker

When creating a Broker instance, you need to pass the server url, broker id and broker secret. The broker id and secret needs to match the secret registered at the server.

CAVEAT: The broker id MUST be alphanumeric.

Attach

Before the broker can do API requests on the client's behalf, the client needs to attach the broker token to the client session. For this, the client must do an HTTP request to the SSO Server.

The getAttachUrl() method will generate a broker token for the client and use it to create an attach URL. The method takes an array of query parameters as single argument.

There are several methods in making the client do an HTTP request. The broker can redirect the client or do a request via the browser using AJAX or loading an image.

use Jasny\SSO\Broker\Broker;

// Configure the broker.
$broker = new Broker(
    getenv('SSO_SERVER'),
    getenv('SSO_BROKER_ID'),
    getenv('SSO_BROKER_SECRET')
);

// Attach through redirect if the client isn't attached yet.
if (!$broker->isAttached()) {
    $returnUrl = (!empty($_SERVER['HTTPS']) ? 'https://' : 'http://') . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
    $attachUrl = $broker->getAttachUrl(['return_url' => $returnUrl]);

    header("Location: $attachUrl", true, 303);
    echo "You're redirected to <a href='$attachUrl'>$attachUrl</a>";
    exit();
}

Verify

Upon verification the SSO Server will return a verification code (as a query parameter or in the JSON response). The code is used to calculate the checksum. The verification code prevents session hijacking using an attach link.

if (isset($_GET['sso_verify'])) {
    $broker->verify($_GET['sso_verify']);
}

API requests

Once attached, the broker is able to do API requests on behalf of the client. This can be done by

  • using the broker request() method, or by
  • using any HTTP client like Guzzle

Broker request

// Post to modify the user info
$broker->request('POST', '/login', $credentials);

// Get user info
$user = $broker->request('GET', '/user');

The request() method uses Curl to send HTTP requests, adding the bearer token for authentication. It expects a JSON response and will automatically decode it.

HTTP library (Guzzle)

To use a library like Guzzle or Httplug, get the bearer token using getBearerToken() and set the Authorization header

$guzzle = new GuzzleHttp\Client(['base_uri' => 'https://sso-server.example.com']);

$res = $guzzle->request('GET', '/user', [
    'headers' => [
        'Authorization' => 'Bearer ' . $broker->getBearerToken()
    ]
]);

Client state

By default, the Broker uses the cookies ($_COOKIE and setcookie()) via the Cookies class to persist the client's SSO token.

Cookie

Instantiate a new Cookies object with custom parameters to modify things like cookie TTL, domain and https only.

use Jasny\SSO\Broker\{Broker,Cookies};

$broker = (new Broker(getenv('SSO_SERVER'), getenv('SSO_BROKER_ID'), getenv('SSO_BROKER_SECRET')))
    ->withTokenIn(new Cookies(7200, '/myapp', 'example.com', true));

(The cookie can never be accessed by the browser.)

Session

Alternatively, you can store the SSO token in a PHP session for the broker by using Session.

use Jasny\SSO\Broker\{Broker,Session};

session_start();

$broker = (new Broker(getenv('SSO_SERVER'), getenv('SSO_BROKER_ID'), getenv('SSO_BROKER_SECRET')))
    ->withTokenIn(new Session());

Custom

The method accepts any object that implements ArrayAccess, allowing you to create a custom handler if needed.

class CustomStateHandler implements \ArrayAccess
{
    // ...
}

This can also be used with a mock object for testing.

sso's People

Contributors

abemedia avatar aldinokemal avatar casperlaitw avatar crzidea avatar gurubobnz avatar jasny avatar jeremylwright avatar kimjangwook avatar ludovic-berlemont-oxand avatar madsnow avatar mazraara avatar mrswiss avatar munvier avatar nishat-propertyloop avatar poratuk avatar rubenstolk avatar subdee avatar svenstm avatar tengenjulian avatar tjroger 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  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  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  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  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

sso's Issues

Still in README.md

When the session is attached you can do actions as login/logout or get the user's info.
$broker = new Jasny\SSO\Broker($serverUrl, $brokerId, $brokerSecret);
$broker->attach();
//$user = $boker->getUserInfo();
$user = $broker->getUserInfo();
echo json_encode($user);

Good job .i have a question .can you help me ?

The client requests the index page at the broker. The broker will request user information from the server. Since the visitor is already logged in, the server returns this information. The index page is shown to the visitor.

Each client request to the index page ,the broker has to request user information from the server ,though the visitor is already logged in.

Is it reasonable?

I mean it takes 1second to complete curl request to get information from the server. Cost too much than traditional session login .

Hope your answer

sso server scalability

I have SSO server running with AWS autoscaling group with 1 instance at the moment, now if I have to make it scalable (more than 1 instance) what is the good way to do it? I see we are using linking of the session by $sid from the cache. Seems, I need to modify createCacheAdapter and to store same information outside server? What is a good solution for it?

Debug mode

To many users have issues with setting up Jasny SSO. To solve this, we should add a debug mode.

In debug mode we might add HTTP headers or even additional dialogs which help the user find out why things aren't working.

SSO in existing site which has always login

Hey Arnold,

thank you for this great SSO Implementation. Its very easy, secure and extendable.

I used it for this case:

I habe a wordpress site, and if it is logged in, other external sites must be also logged in.

So in that case I did the following on server side (wordpress)

$broker = new Jasny\SSO\Broker('http://www.xxxx.de/sso/server/', 'xxxx', 'xxxx');
$ssoServer = new MySSOServer();
$ssoServer->startUserSession();

if (is_user_logged_in()) {
    $ssoServer->setSessionData('sso_user', 'xxxx');
} else {
    $ssoServer->setSessionData('sso_user', null);
}

This snipped is called after wordpress logout/login as callback.

It that a good aproach and correct?, because it works. I did not want to create a new login on wordpress and want to use the existing login.

Best Regards
Sven

I got "Expected application/json response, got text/html" when logout.

When I click logout I got "Expected application/json response, got text/html"
Error1

So I try to capture data from (Broker->Server) and I got this(HTTP Error 411).
Error2

I try to fix this Error by edit(sso/src/Broker.php) line 254
I change
public function logout() { $this->request('POST', 'logout'); }
to
public function logout() { $this->request('GET', 'logout'); }
Error3

And, it works fine for me.

I want to know that my hotfix will affect my website security or not? Since, I don't know what I'm doing.

Sorry for my poor English.

Implementing two Websites User Auth, as Master-Slave duo, using your SSO for authentification in Slave?

Hello,

I try to implement a Master-Slave solution, made from two websites which need a common sign-in method. In theory, the Users sign in into Master, where they have access to a Private Area after login, with diverse pages.

Also, there are available some Files for download and a (AJAX) WebChat (which use of course, the Website's Auth System to find the users & Co.).

My intention is to move those (private) Files and the WebChat engine on a secondary website, while they can be available only under Authentication. But, what I want is that Secondary Website to transparently authenticate and un-authenticate the Users, following the Master website.
In theory, when the User is authenticated in Master, it should be automatically authenticated in Slave, with the same credentials as Username, Real Name, etc. An that User have access to his Private Files and WebChat, like those are hosted in the Master, where he is logged in.

You are kind to offer some suggestions about how can this design can be implemented using your SSO?

Expected application/json response, got text/html error

Hello,

When I try the examples on my virtual machine I have no problem and that's works fine but when I put it into a web server, I have this error every time Expected application/json response, got text/html

Do you know why I have this error ?

Thank's a lot,

PetitBX

Remove client address from checksum

The client address from the checksum should be removed, be this can change. Especially when you use an app on a mobile device the IP address change frequently.

Problem en remote server

I tested locally and works well. but when I try try from different subdomains I have problems

Broker didn't send a session key

The broker session id isn't attached to a user session

Hi,
After few hours I gave up and decide to ask for help...
When I try to login "The broker session id isn't attached to a user session" is returned every time.
When I first land on login page SSO token is generated under cookies, but after pressing "Log in" button, cookie disappears and error is returned. I tried both methods for broker (AJAX, non-AJAX), same error every time.
Could the problem be that both Broker and server are running on same machine with same IP and only different port (Broker 55556, Server 55557)?

Can you please point me in right direction where to possibly look for errors?

Thank You!

Fix demo's

The demo websites are currently down. I should set them up under other domains.

One Login Form (Server)

I have implement your code to one form Login on server. But, I have stuck.

Broker > attach to server
Broker > Server::GetUserInfo (Curl) > False > Server::Login Form (Redirect) > Broker (Redirect)
Broker > Server::GetUserInfo (Curl) > No Session (This fail)

Can I use your code for that rule?
I know the session is not shared. But, how can I get it? Any Idea?

Examples not working

All "require_once DIR . '/../../vendor/autoload.php';" should be replaced by "require_once DIR . '/../../../../../vendor/autoload.php';"

Too many session files could not be deleted

Hi,jasny
Your code works well in my project.
My question is that ,it creats a lot of session files in session save path and could not be deleted automaticly,how to fix it ?

Error handling between server and brokers

Hi!

If the server of SSO restart, all sessions are deleted.

All brokers receive this error :

Unknown client IP address for the attached session

But all brokers have a valid cookie, then they do not attach to server.
All current users must remove manually cookies to successfully reconnect in broker.

The same problem occurs on SSO file cache when expired or deleted

I have one idea I have been working on, hoping you’ll take time to take a look at PR I’d send.

Thanks

Install through composer

Your README.md reads

Install this library through composer

composer request jasny/sso

Is that means composer require jasny/sso ?

Fix examples

The examples should work pretty much as the old demo (on the current master branch) does.

It should create a concrete SSOServer class that extends Jasny\SSO\Server.

Can't install jasny/sso using composer

I have difficulty installing jasny/sso, below are the error I'm getting when I tried to "composer require jasny/sso":-

Using version ^0.3.0 for jasny/sso
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - The requested package jasny/sso No version set (parsed as 1.0.0) is satisf
iable by jasny/sso[No version set (parsed as 1.0.0)] but these conflict with you
r requirements or minimum-stability.


Installation failed, reverting ./composer.json to its original content.

unable to auto login

i logged in on s1 then i went to s2 still the login form is show.

i created a demo, no changes has been made in the source code except for the server url.and the broker for each domain. server url is http://85.214.200.88/sso/.

s1: http://arnelqlabarda.com/testing/sso/
s2: http://85.214.200.88/sso/login/

i checked the server tmp dir.. this is what i have.

-rw-r--r-- 1 www-data www-data   26 Feb  8 09:52 SSO-BINCK-f1f8f90da0380e4cc44a781b67136664-b1e1f0927c2dc7fc9fd1586a2fb47d3d
-rw-r--r-- 1 www-data www-data   26 Feb  8 09:52 SSO-LYNX-a54cd54a56a688309cb301ff9739d978-5f14e5d9a1e3f8e57d1f890921349c64
-rw-r--r-- 1 www-data www-data   26 Feb  8 09:52 SSO-UZZA-28f7a678f27c5bd01d030d2d6374986b-0744949136594cfe0aab565d9b620591

Expected application/json response, got text/html after moving to web server

I've problem with getting error "Expected application/json response, got text/html ". On my localhost it works well but not from web server. I'm running Pl*sk and base with FatFreeFramwork, tried to switching php version but nothing happens, even to put "curl_setopt($ch, CURLOPT_FOLLOWLOCATION, true);" into broker.php as @petitbx said. But for php 7.0 i got this error "Broker didn't send a session key".
Thx

php 7.1

php 7.0.15

Session Lost on Second Broker

Hi,
I tried to implement "Single Sign-On" within our applications. It works fine in localhost but when we tried to deploy this on web then it work with in single broker. It mean when we jump on second broker the session lost and login box start displaying instead of displaying index.php of second broker.

localhost/sso-live/broker1
localhost/sso-live/broker2

foo.com/sso-live/broker1
foo.com/sso-live/broker2

Please help me out to resolve this.

Use Authentication header with bearer token

Sending the SSO session token as query parameter can be unsafe. These typically appear in access and errors logs. This means ppl who have access to these logs (developers, devops, etc) can abuse these tokens.

Instead we should send an Authentication Bearer header with the session token. See RFC 6750.

For BC the SSO server should accept both.

autoload.php?

Hi!

I downloaded your SSO,and when i'm tryied out one of your example (server),the PHP gives me a require error. I serached for autoload.php,but i'm didn't find it.

require_once __DIR__ . '/../../vendor/autoload.php';

Can you help me with this problem?

Thank you in advice!

Integration with Symfony

Hello.
After a bit of reading on OAuth and SSO I was aiming to use this library rather than implementing OAuth2 for a SSO, which seems to be a bit of a trend rather than a real need.
In my case I only have trusted parties, so I don't need any level of Authorisation. What I need is Single Authentication and shared session, just what this library does.

The documentation says that the server class can be utilised in MVC as controller or library.
Does anyone ever integrated this with Symfony. As proof of concept I could use this library in my project between various technologies (Drupal, shopify etc) as service providers and a Symfony (full stack framework) as Id provider I utilised the @jasny examples as SPs and reproduced a IdP in the default symfony controller as follows below.

The AppBundle\SSO\SSOServer extends Server exactly like Jasny does and it's a copy of the MySSOServer you find in the examples folder. My intention was get a proof of concept working, so for the moment is convenient working with that.

The only real difference is the return in the Symfony indexAction. In general a symfony controller must return a response so I used a return new JsonResponse to actually pass stuff back to the broker.

I could have everything working (token generation, session key, redirection). But when I tried to log-in on the brokers I would get a "Failed Login" error (coming from the Broker itself - line 16 of the login.php example if ($_SERVER['REQUEST_METHOD'] == 'POST') $errmsg = "Login failed";)

Now the question: did somebody ever used this library with Symfony or have any suggestion on how to do it properly.


class DefaultController extends Controller
{
    /**
     * @Route("/", name="homepage")
     */
    public function indexAction(Request $request)
    {

//Symfony Dependency Injection here:
        $container = new ContainerBuilder();

        $container->register('server', 'AppBundle\SSO\SSOServer');
        $ssoServer = $container->get('server');

        $command = isset($_REQUEST['command']) ? $_REQUEST['command'] : null;

        if (!$command || !method_exists($ssoServer, $command)) {
           return new JsonResponse(array('error' => 'Unknown $command'));
        }
        return new JsonResponse(array($ssoServer->$command()));
    }
}

Deployment process

Hello,
Can you please tell me what is the procedure to deploy this in an aws configuration?
I have tried to run the command php -S SERVER_IP:9000 -t sso/server and then when i try to open my site then its just loading and loading... is there any step that is left while deployment??

There is no much data available for its deployment although ive tested the whole mechanism in my local machine but its not working in live as it does in local. I have double checked all the confguration at deployment.
Iam a bit confused that do i need to run the above stated command or should a virtual host pointed to above directory and host must do the stuff?

Q: How to implement "remember me" option

Is there a simple way to implement a "remember me" functionality like known from other sites like Paypal, Facebook, etc.? ("This is a private computer. Keep me logged in until i nuke my browser")

Remove client IP from checksum

This isn't required to make SSO work. It gives major problems, especially when clients are on mobile devices. The problems outweigh the added security.

Abstract authenticate method for server

The login method should call $this->authenticate(), which is an abstract method. To create a server, the developer must create a class that extends the Jasny\SSO\Server class and implements this method.

The authenticate method must return a Jasny\ValidationResult object.

Userinfo method on SSO\Server.php is null

I try to make login from a broker to the server, but always the server return userinfo method like null, this problem prints on broker: Expected application/json response, got text/html

image

I try delete all cookies and all sessions but the problem is not fixed

image

CAS compatibility

I want to implement this with a broker application that only supports CAS v3.0 or SAML v2.0.

Do you think your package would be able to help with this?

confusion

If every broker has a unique brokerId and secret?

Session Cache grows until never

As already mentioned at #13, there is no session GC. In my case, using the File-adapter, had a cache-folder containing millions of files (sadly I didn't do a count before cleanup). find . -mtime +5 -exec rm {} \; did at least run for 20 minutes - now I'm at 134806 files. So maybe at least 2,5 million files before.

https://github.com/desarrolla2/Cache/blob/master/src/Adapter/AbstractAdapter.php#L59

Not a single concrete adapter implements a clearCache logic.

Please don't close this issue, just because it is a "missing feature" in an external library.
Consider implementing a cleanup within the SSO-Server class or replace desaroll2/cache with another PHP-cache library.

Any Help implementing it with Laravel 4 or 5

Hi,

First of the congrats and thanks for this wonderful library

Please do favour and help me implementing it with laravel.

I think only big problem i could get is with merging the vendor folder because what you used is already used in Laravel.

Kindly Help. Thanks!

Use cache library to link sessions

Remove the option to use symlinks to link sessions. Instead use the desarrolla2/cache library to store the session id for the broker (replacing SSO\Session line 157 to 169.

Add a protected function createCacheAdapter(), which is called in the constructor. By default the function will create a file cache adapter, using /tmp/sso-sessions as directory. This function can be overloaded when extending the SSO\Server class.

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.