|
Network game user accounts (for a.cc members) |
Mark Oates
Member #1,146
March 2001
|
I'm wondering if it's possible to use existing allegro.cc member accounts for an allegro multiplayer online game network. Similar to how Nintendo accounts allow for playing games on the Nintendo network, Steam accounts allow for all the Valve multiplayer games, Apple ID for iOS games, etc. I want to investigate something similar for Allegro. I want to avoid going through the whole process of new registration + validation with all that new infrastructure, and I would like the accounts to be the same familiar allegro.cc usernames / avatars that we know so well. I know that a similar process is used to facilitate enrolment in SantaHack and SpeedHack, what about enrolling for actual multiplayer games? What would that entail? I've made a rudimentary TCP multiplayer game service (with boost::asio, compiles on Linux & Windows) that's volleying messages to connected clients from a persistent dedicated server. I've been thinking about how I could extend it into something we could all play around with (perhaps provided as an addon and a dedicated service similar to Unity3D's "Photon"). My idea for a minimum viable proof-of-concept is to create an "Allegro Land" game (think Miiverse or Nintendo Land's courtyard), where we could walk around with custom avatars (in 3D) and chat. The prototype I have now is already syncing 2D bounding boxes and talk bubbles between clients. -- |
Matthew Leverton
Supreme Loser
January 1999
|
There would be no way to know if such an authentication method were secure. The client could easily be stealing the passwords. The game would have to launch a browser to use for authentication, which would then need to pass data back to the game. Technically feasible if the game is configured to launch via a custom scheme, but cumbersome. Alternatively, The website could generate a one time pass code for use with the game, but that wouldn't be seamless either. |
Chris Katko
Member #1,881
January 2002
|
The other issue would be whether Matthew is okay with a possibly popular game flooding his website with authentication requests and possible influx of non-programmers here. Just something to consider. -----sig: |
Felix-The-Ghost
Member #9,729
April 2008
|
Mark Oates
Member #1,146
March 2001
|
Matthew Leverton said: The game would have to launch a browser to use for authentication, which would then need to pass data back to the game. Technically feasible if the game is configured to launch via a custom scheme, but cumbersome. So you're saying, for example, the game might have a login button, and upon clicking:
Is this what you mean? That's cool. I'm guessing a socket would need to be kept open between allegro.cc and the game while it's waiting. Felix-The-Ghost said: Isn't that what the Minecraft launcher does? Interesting. So instead of launching a browser, you would have a small separate standalone program for the sole purpose of authenticating members. The authentication that the standalone program provides would be available to any games that are running (maybe with shared memory or something). So the process might work something like this:
At first I thought opening a browser would be convoluted, but now I'm thinking it seems much more liquid than a standalone login program. -- |
Matthew Leverton
Supreme Loser
January 1999
|
Mark Oates said: allegro.cc signals back to the game that the user is valid and member number X. It could do that, yeah. I was saying that it could redirect the browser to foobar://login?token=foo. Assuming your application has registered that scheme, then the application would take over from there (validating the token in secret). But if you already have a server up and running for the game, your interpretation would be slightly more simple. Quote: the authentication that the standalone program provides would be available to any games that are running (maybe with shared memory or something). That sounds like it would be insecure. The client would have to directly authenticate via the server at some point, or else the whole thing could be spoofed. Although I suppose if this standalone program simply relayed some content that was signed by the server using a secret key (that no client has), then you could create some sort of trust. |
Mark Oates
Member #1,146
March 2001
|
Matthew Leverton said: That sounds like it would be insecure. The client would have to directly authenticate via the server at some point, or else the whole thing could be spoofed. For the standalone concept, the standalone would generate a token that any game would then use to directly authenticate with a.cc. Rather than the game validating an a.cc user with username/password, it would validate with the username/token that was created by the standalone<->a.cc. I seem to like the browser idea better, though. After logging in on a desktop environment, a landing page of "You're logged in! Return to your game. (click here to close)" would probably be good enough. For small online allegro games, it's probably not reasonable to expect users to add a new URI scheme to their registry (unless it's more trivial that I think). I wonder how this concept would work in a mobile environment. In that case, I can see the foobar://login?token=foo would be more necessary - it would seamlessly "escape" out of the browser and back to the game. I'm not sure the best way to authenticate the client identity with the network server, however. Perhaps a.cc could send a key to both the server and the user when the login occurs, and as long as they both match when the client sends data to the server it could be considered valid. It seems reasonable. A client, a network service, and a.cc communicating over TCP. -- |
beoran
Member #12,636
March 2011
|
It's not necessary to use a browser, just use an HTTP client library like libcurl. (http://curl.haxx.se/libcurl/). The allegro.cc server could then be extended with an API that produce, e.g JSON. to check the logins. Just throwing a few ideas in here. |
Peter Hull
Member #1,136
March 2001
|
This stuff makes my head spin - but - are you effectively asking a.cc to be an OpenID provider?
|
Matthew Leverton
Supreme Loser
January 1999
|
beoran said: It's not necessary to use a browser, just use an HTTP client library like libcurl. Right, but then you have to trust that the client isn't stealing your credentials. Peter Hull said: This stuff makes my head spin - but - are you effectively asking a.cc to be an OpenID provider? It already is (in concept). The wiki and Speedhack share authentication with a.cc. |
beoran
Member #12,636
March 2011
|
Well if it's an open source game then you can rely the client. If it's binaries you have to sign them and trust the author. Same goes for anything anyway. If either the client or the server is unreliable, then you can get into problems. Still, one thing that could help would be be to have a separate password per application. Every app can register itself and a user-chosen password. You'd have to log in once in a.cc to approve those logins. Well, just some brainstorming. |
Mark Oates
Member #1,146
March 2001
|
I have a naive implementation of the browser-launching solution that works pretty well. The trick for this technique is that the server does not complete the HTTP response to the game until the user has successfully authorized. Here are some pretty pictures: Run the command line 'game': it launches the browser to the URL: enter credentials (clock is counting down from the server) credentials validated on the browser and the 'game' is notified. A more complete description of the implementation is as follows: 1. The game launches. Keep in mind, I did this in a day so there's some redundancy and needs refactoring. I did this all on Windows in localhost - I'll check it on a remote Linux server tomorrow and probably put it up on GitHub. -- |
Chris Katko
Member #1,881
January 2002
|
Wow, keep up the good work! -----sig: |
LennyLen
Member #5,313
December 2004
|
So how are you going to assure people that you're not stealing their passwords?
|
Mark Oates
Member #1,146
March 2001
|
LennyLen said: So how are you going to assure people that you're not stealing their passwords? You would only ever enter your credentials at https://www.allegro.cc. [edit] UpdatesMkay, here are the files on GitHub. Here is the game example program working on Ubuntu while validating the credentials "alex/password" on a remote demo server http://auth.zeoxdesign.com. If anybody wants to try compiling and running this demo, you can use http://auth.zeoxdesign.com as the first argument and use "alex/password" as the username/password. To facilitate discussion, here is the example game program: 1/*
2 This example program requires CURL
3*/
4
5
6#include <iostream>
7#include <string>
8#include <sstream>
9#include <algorithm>
10
11#include <curl/curl.h>
12
13
14struct RequestData
15{
16 std::string auth_domain_name;
17 std::string auth_key;
18 std::string full_response;
19 bool request_remotely_initialized;
20};
21
22
23std::string generate_auth_key(unsigned length = 32)
24{
25 srand(time(0));
26 std::string selection_set;
27 for (unsigned i=0; i<length; i++) selection_set += "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789";
28 std::random_shuffle(selection_set.begin(), selection_set.end());
29 return selection_set.substr(0, length);
30}
31
32
33void launch_browser_to_login(RequestData *request_data)
34{
35 std::string validate_auth_url = request_data->auth_domain_name + "/validate_auth.php?auth_key=" + request_data->auth_key;
36
37#ifdef _WIN32
38 #include <windows.h>
39 // this one is non-blocking
40 ShellExecute(NULL, "open", validate_auth_url.c_str(),
41 NULL, NULL, SW_SHOWNORMAL);
42#elif defined __APPLE__
43 std::stringstream command;
44 command << "open " << validate_auth_url;
45 // this one is blocking
46 system(command.str().c_str());
47#else
48 // assume a Linux environment
49 std::stringstream command;
50 command << "xdg-open " << validate_auth_url;
51 // this one is blocking
52 system(command.str().c_str());
53#endif
54}
55
56
57
58size_t CURL_buffer_write_callback(char *ptr, size_t size, size_t nmemb, void *userdata)
59{
60 std::string new_data;
61 RequestData *request_data = static_cast<RequestData *>(userdata);
62 for (unsigned i = 0; i < size*nmemb; i++)
63 new_data.push_back(ptr[i]);
64
65 std::cout << new_data; // comment this out for a "quiet" mode
66
67 request_data->full_response += new_data;
68
69 // check that the expected magical phrase has been provided.
70 if (!request_data->request_remotely_initialized
71 && (request_data->full_response.substr(0, 52) == "Authorization request staged. Awaiting user login..."))
72 {
73 request_data->request_remotely_initialized = true;
74 std::cout << std::endl << "Authorization request recieved by the server. Launching browser..." << std::endl;
75 launch_browser_to_login(request_data);
76 }
77
78 return size*nmemb;
79}
80
81
82int send_stage_auth_request_to_authority(std::string auth_domain_name)
83{
84 RequestData *request_data = new RequestData;
85 request_data->auth_key = generate_auth_key();
86 request_data->auth_domain_name = auth_domain_name;
87 request_data->request_remotely_initialized = false;
88
89 std::string auth_url = request_data->auth_domain_name + "/stage_auth_request.php?auth_key=" + request_data->auth_key;
90
91 std::cout << "sending request to " << auth_url << std::endl;
92
93 // start the curl operation
94 CURL *curl = curl_easy_init();
95 if (curl)
96 {
97 CURLcode res;
98 curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CURL_buffer_write_callback);
99 curl_easy_setopt(curl, CURLOPT_WRITEDATA, request_data);
100 curl_easy_setopt(curl, CURLOPT_URL, auth_url.c_str());
101 res = curl_easy_perform(curl);
102 // curl_easy_perform is blocking. If this implementation were to be used in an a game,
103 // then this send_stage_auth_request_to_authority() function should be executed as a thread.
104 // that way the game could provide status feedback and/or play a 'waiting' animation.
105 // Any status info be extracted during the CURL_buffer_write_callback and accessible
106 // through a RequestData object (and should probably be sealed in a mutex)
107 if (res == CURLE_OK)
108 {
109 std::cout << "curl request successfully completed." << std::endl;
110 if (!request_data->request_remotely_initialized) std::cout << "ERROR: The authorization server did not respond as expected." << std::endl;
111 }
112 else
113 {
114 std::cout << "curl Error " << res << ": " << curl_easy_strerror(res) << std::endl;
115 }
116 curl_easy_cleanup(curl);
117 }
118 else
119 {
120 std::cerr << "Error: Could not initialize curl" << std::endl;
121 return 1;
122 }
123 return 0;
124}
125
126
127
128int main(int argc, char* argv[])
129{
130 if (argc == 1)
131 {
132 std::cerr << "usage: acc_auth_ex http://www.someauthdomain.cc" << std::endl;
133 return 1;
134 }
135
136 std::cout << "Are you ready? Ready to start the authorization process? :D Press ENTER and you will be wisked away to the authorization page for " << argv[1] << " on your browser." << std::endl;
137 std::cin.ignore();
138
139 send_stage_auth_request_to_authority(argv[1]);
140}
-- |
jmasterx
Member #11,410
October 2009
|
How does the browser portion work? As in, once the user has authenticated through the browser, what happens? How does the c++ app get notified? Agui GUI API -> https://github.com/jmasterx/Agui |
Mark Oates
Member #1,146
March 2001
|
The request that is initiated by the c++ app to the server is left "hanging". A user then logs in through a browser with the auth_key. When that happens, then the "hanging" request is completed and closed with the confirmation response. [edit] There are two connections... one by the c++ app to the server (left hanging)... and then a completely different, typical login through a browser. -- |
jmasterx
Member #11,410
October 2009
|
That's interesting. I did not think a request could hang for so long. What's the timeout? Agui GUI API -> https://github.com/jmasterx/Agui |
Mark Oates
Member #1,146
March 2001
|
In this case it's set for 3 minutes. On the server, the script is kept from timing out with set_time_limit(). Assuming there isn't a global override somewhere, it will work. The server is also sending the current countdown integer every 2 seconds, so data is still being transferred while it's hanging. Also, apparently, sleep() does not count towards the execution time of the script. It's set here: https://github.com/MarkOates/acc_auth_server_PHP/blob/master/stage_auth_request.php#L26-L32 On the c++ app, CURL never times out. But it should probably be set with CURLOPT_TIMEOUT. -- |
jmasterx
Member #11,410
October 2009
|
Cool A while back I wanted to integrate Facebook login into my game but decided against it because I could not figure out how I would get the token from the browser, but I guess something like this might work. Agui GUI API -> https://github.com/jmasterx/Agui |
bamccaig
Member #7,536
July 2006
|
I think there are a few issues with this design. For one thing, I wouldn't trust that the browser will block. I would expect at least on some platforms that the system call to launch the browser would communicate with an existing instance of the browser, pass the URL request on to that, and exit immediately. For this reason I think that communicating with any browser from an external process will likely be problematic. Of course, an alternative solution might be asking the user to transfer a token from the browser to the application (i.e., steam does something like this via E-mail to verify that you are who you say you are, but that's in addition to authenticating, not part of the authentication itself). This would obviously not be very secure, and an onlooker could again potentially steal it. At least, if the game ties the request token with the response token then it should prevent abuse unless the "game" chooses the same token for both users. Which leads me to the next point: there should probably be a proxy server between the game and A.cc. The server should be responsible for generating the request token and initiating the background connection with A.cc, not the client application. It would be too easy to hack the game executable to play nicely with the weaknesses of this technique. In addition, command line arguments are often exposed to all users of a system meaning that if your token was passed to the browser via a querystring via a command line argument then a malicious user on the system could theoretically load up that same URL and beat you to it (unless the server is going to quickly invalidate it upon first use, but that could lead to user friendliness issues if they screw up their credentials the first time). In theory, all a malicious user could do with it is cause you to log in as themselves, which does seem odd, but that could still be abused (theoretically). Lastly you're unnecessarily allocating your data on the heap and appear to be leaking the memory (which doesn't matter for this example, but is sloppy). I'm really not sure that there is a trusted and secure way to do this... -- acc.js | al4anim - Allegro 4 Animation library | Allegro 5 VS/NuGet Guide | Allegro.cc Mockup | Allegro.cc <code> Tag | Allegro 4 Timer Example (w/ Semaphores) | Allegro 5 "Winpkg" (MSVC readme) | Bambot | Blog | C++ STL Container Flowchart | Castopulence Software | Check Return Values | Derail? | Is This A Discussion? Flow Chart | Filesystem Hierarchy Standard | Clean Code Talks - Global State and Singletons | How To Use Header Files | GNU/Linux (Debian, Fedora, Gentoo) | rot (rot13, rot47, rotN) | Streaming |
Mark Oates
Member #1,146
March 2001
|
bamccaig said: I think there are a few issues with this design. For one thing, I wouldn't trust that the browser will block. I would expect at least on some platforms that the system call to launch the browser would communicate with an existing instance of the browser, pass the URL request on to that, and exit immediately. No part of the design expects or requires a blocking browser process. Non-blocking is the preferred behavior. When developing on windows, throwing a system("open browser") in there for Linux/Mac is just easier. Dropping a fork() in there or ensuring a background (&) process would produce nicer behavior. Quote: For this reason I think that communicating with any browser from an external process will likely be problematic. No process is communicating with the browser, so there's no problem. The app only communicates with the authenticating server. It also launches the browser to a URL, but has no other interactivity with the browser than that. Quote: In theory, all a malicious user could do with it is cause you to log in as themselves, which does seem odd, but that could still be abused (theoretically). Your attempt at the web login would fail, and you would identified as "fake_usr_8739". Well, nothing seems out of the ordinary here! *keeps playing* The cool thing about this design is that no identifiable information is asked of you. The only thing that is provided to the network game server is 1) your IP address and 2) that you are allegro user #7536, that's it. Your login authorization is on http://www.allegro.cc and nothing changes with that. If you're logged in already, it's possible that the design could be improved to only require an "approve" button. Any additional information about your identity on a.cc (avatar, username) is public anyway. Ponder on it a bit more? It's cool, it works. Quote: I'm really not sure that there is a trusted and secure way to do this... Then stop relying on the security of your browser for day-to-day stuff, because it could be compromised and stealing all ur loginz. Quote: appear to be leaking the memory (which doesn't matter for this example, but is sloppy). Yea, I forgot to delete that RequestData didn't I? Bam, I really appreciate your feedback. I think that if you ponder on it a bit more you'll see that some of the points you brought up are already addressed and/or are not a concern. If you spot more stuff, or see something, please bring it up! It might just need some clarification. -- |
|