Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Question: grpc-gateway non gRPC auth. #6643

Closed
hexfusion opened this issue Oct 13, 2016 · 25 comments
Closed

Question: grpc-gateway non gRPC auth. #6643

hexfusion opened this issue Oct 13, 2016 · 25 comments
Assignees
Labels

Comments

@hexfusion
Copy link
Contributor

I am creating a Perl Etcd v3 client utilizing the grpc-gateway and I am having problems using authentication token during request.

Workflow

  1. Generate token
  2. Pass token in header during request.

Documentation on this is light I have tried various headers from looking at the source including.

  • Grpc-Metadata-Authorization: $token
  • Authorization: Token $token
  • Authorization: $token
  • Authorization: Bearer $token
  • authorization ...

I have also tried encoding the token with base64. But each time the content error is {"Error":"auth: revision in header is old","Code":2}

My question is does the grpc-gateway auth work? If yes can you please provide an basic example of usage.

@xiang90
Copy link
Contributor

xiang90 commented Oct 13, 2016

/cc @mitake Can you take a look?

@mitake
Copy link
Contributor

mitake commented Oct 14, 2016

  1. Pass token in header during request.

@sbatschelet how are you doing it? Does perl have gRPC client? clientv3 of etcd is attaching the token to a connection with per RPC credential mechanism (grpc.WithPerRPCCredentials()). The same mechanism must be used (I'm not familiar with the status of perl's gRPC support...).

@hexfusion
Copy link
Contributor Author

hexfusion commented Oct 14, 2016

@mitake my understanding and reason for writing this module for Perl was this statement from POD. "For languages with no gRPC support, etcd provides a JSON grpc-gateway. This gateway serves a RESTful proxy that translates HTTP/JSON requests into gRPC messages." from https://github.com/coreos/etcd/blob/master/Documentation/dev-guide/api_grpc_gateway.md

So why would authentication require gRPC support? I really appreciate what you guys are doing with the gateway but non gRPC languages still need the ability to authenticate against the it.

@hexfusion hexfusion changed the title Question: grpc-gateway auth token Question: grpc-gateway non gRPC auth. Oct 14, 2016
@xiang90
Copy link
Contributor

xiang90 commented Oct 16, 2016

Workflow

  1. Generate token
  2. Pass token in header during request.

Can you please provide more details? How do you generate the token? How do you pass in the token?

We do not really maintain the gateway code. So I do not know if it works or not. But we would like to help you to debug to some extent.

@mitake
Copy link
Contributor

mitake commented Oct 17, 2016

@sbatschelet sorry I misunderstood your intention.

So why would authentication require gRPC support?

v3 auth depends on gRPC's credential mechanism for attaching a token to a connection because it can be used by all languages supported by gRPC in an easy and safe manner (and it doesn't care how the token is treated internally by gRPC). But your perl client wouldn't need the exactly same mechanism if the grpc gateway can use a token supplied by a client. Currently the mechanism wouldn't be implemented in grpc proxy side e.g. which field of request is used for the token isn't determined yet (sorry I'm not familiar with grpc proxy). But implementing it won't be a difficult task if you want it. If you want to work on it, I'll be able to help.

@hexfusion
Copy link
Contributor Author

@xiang90 here is my process.

I create a Etcd3 client object via connect through my module.

$etcd = Etcd3->connect($host, { username => $u, password =>$p, ssl => '1'});

which when built has the following data

$VAR1 = bless( {
                 'api_root' => 'https://ob1.hexfusion.local:2379',
                 'headers' => {
                                'Authorization' => 'ngJMOXyGKexVebld.892262',
                                'Content-Type' => 'application/json'
                              },
                 'password' => 'xxxx',
                 'ssl' => '1',
                 'port' => '2379',
                 'auth_token' => 'ngJMOXyGKexVebld.892262,
                 'host' => 'ob1.hexfusion.local',
                 'auth' => 1,
                 'username' => 'root',
                 'api_path' => 'https://ob1.hexfusion.local:2379/v3alpha',
                 'api_prefix' => '/v3alpha'
               }, 'Etcd3::Client' );

When the object is created it also builds the auth token and then attaches that token to a header which we will pass on POST. The request for the token looks like this.

            'request' => {
                                'content' => '{"token":"ngJMOXyGKexVebld.892262"}',
                                'protocol' => 'HTTP/1.1',
                                'success' => 1,
                                'reason' => 'OK',
                                'status' => '200',
                                'url' => 'https://ob1.hexfusion.local:2379/v3alpha/auth/authenticate',
                                'headers' => {
                                               'content-length' => '35',
                                               'date' => 'Mon, 17 Oct 2016 23:46:51 GMT',
                                               'grpc-metadata-trailer' => [
                                                                            'Grpc-Status',
                                                                            'Grpc-Message'
                                                                          ],
                                               'content-type' => 'application/json'
                                             }
                              },
                 'endpoint' => '/auth/authenticate',
                 'json_args' => '{"password":"xxxx","name":"root"}'
               }, 'Etcd3::Auth::Authenticate' );

So basically I am posting {"password":"xxxx","name":"root"} to https://ob1.hexfusion.local:2379/v3alpha/auth/authenticate and getting {"token":"ngJMOXyGKexVebld.892262"} in return.

As far as the HTTP headers I can pass whatever would be required but Authorization looked promising via https://github.com/grpc-ecosystem/grpc-gateway/blob/v1.1.0/runtime/context.go#L51

Finally I would try to pass the token in the header during a transaction like a put. Which does not work. Hopefully we can find a solution :).

$VAR1 = {
          'protocol' => 'HTTP/1.1',
          'content' => '{"Error":"auth: revision in header is old","Code":2}',
          'headers' => {
                         'content-length' => '52',
                         'content-type' => 'application/json',
                         'grpc-metadata-trailer' => [
                                                      'Grpc-Status',
                                                      'Grpc-Message'
                                                    ],
                         'date' => 'Mon, 17 Oct 2016 23:46:51 GMT'
                       },
          'url' => 'https://ob1.hexfusion.local:2379/v3alpha/kv/put',
          'success' => '',
          'status' => '500',
          'reason' => 'Internal Server Error'
        };

@xiang90
Copy link
Contributor

xiang90 commented Oct 18, 2016

Can you try to use cURL to rewrite the commands? It would be easier for @mitake and @gyuho to reproduce. Thanks a lot!

@hexfusion
Copy link
Contributor Author

hexfusion commented Oct 18, 2016

@xiang90 sure I guess it would be something like this.

Create token

curl -H "Content-Type: application/json" -X POST -d '{"password":"xxxx","name":"root"}' https://127.0.0.1:2379/v3alpha/auth/authenticate

Pass token

curl -H "Content-Type: application/json" -H "Authenticate: ngJMOXyGKexVebld.892262" -X POST -d '{"key": "Zm9v", "value": "YmFy"}' https://127.0.0.1:2379/v3alpha/kv/put

@mitake
Copy link
Contributor

mitake commented Oct 20, 2016

@sbatschelet the difficulty of supporting auth in the proxy comes from that the gateway code is generated by swagger: https://github.com/coreos/etcd/blob/master/etcdserver/etcdserverpb/rpc.pb.gw.go . Modifying the generated functions and add attach a given token to a connection is not difficult, but editing the machine generated code is of course forbidden.

We need to solve the below 2 problems:

  1. Add a new option to the http interface for passing a token to the proxy. In the above example, you are using Authenticate: field of the options but it isn't used by the proxy yet.
  2. Let the generated code use the passed token as their per RPC credential.

They would be matters of swagger usage. Could you check how to support these requirements via swagger? (sorry I don't know swagger detail...)

@hexfusion
Copy link
Contributor Author

@mitake ok thank you for the notes I will review this and report.

@hexfusion
Copy link
Contributor Author

@mitake sorry for delay on this I have been busy at wo$k. Have you made any progress on this? I didn't want to double efforts.

@mitake
Copy link
Contributor

mitake commented Nov 16, 2016

@sbatschelet no, I'm not working on checking the swagger usage. Is it possible for you to work on it?

@xjjy1083
Copy link

Can you please provide more details about how to add a new option to the http interface for passing a token to the proxy?

@xjjy1083
Copy link

@mitake Can you please provide more details about how to add a new option to the http interface for passing a token to the proxy?

@mitake
Copy link
Contributor

mitake commented Feb 14, 2017

@xjjy1083 it is described in the above comment: #6643 (comment)
It is a swagger matter. If we can find a way of dealing with metadata in the generated code in swagger, implementing the feature isn't so difficult.

@mitake
Copy link
Contributor

mitake commented Apr 7, 2017

I finished other ongoing auth related changes. I'll work on it from next week (but it would need a time because the task will include lots of searching of the API usage...).

@mitake mitake self-assigned this Apr 7, 2017
@hexfusion
Copy link
Contributor Author

@mitake I am very motivated to solve this problem, if you could offer a little guidance perhaps we can tackle this research collectively.

@hexfusion
Copy link
Contributor Author

@mitake Am I right to assume this is the core of the issue? grpc-ecosystem/grpc-gateway#309 .

@mitake
Copy link
Contributor

mitake commented May 2, 2017

@hexfusion sorry for my late reply. And possibly yes, a way described the stack overflow page (http://stackoverflow.com/questions/32910065/how-can-i-represent-authorization-bearer-token-in-a-swagger-spec-swagger-j) would be what we need. Can you try it?

@hexfusion
Copy link
Contributor Author

@mitake thanks for the notes I will give it a try.

@mitake
Copy link
Contributor

mitake commented May 26, 2017

@hexfusion how about your try? If you need my help, please let me know.

@hexfusion
Copy link
Contributor Author

hexfusion commented May 26, 2017

@mitake I am going to give it a go this weekend and see where I get. Will swing back around for assistance next week if I can't make progress, thanks!

@hexfusion
Copy link
Contributor Author

hexfusion commented May 28, 2017

@mitake PR #7999 works for me. Below is an example of usage, let me know what you think. This makes use of direct access of Authorization header key facilitated by grpc-gateway.

# add root user
curl -L http://localhost:2379/v3alpha/auth/user/add \
    -X POST -d '{ "name":"root", "password":"toor" }'

# add root role
curl -L http://localhost:2379/v3alpha/auth/role/add \
    -X POST -d '{ "name":"root" }'

# grant root user root role
curl -L http://localhost:2379/v3alpha/auth/user/grant \
    -X POST -d '{ "user":"root", "role":"root" }'

# enable auth
curl -L http://localhost:2379/v3alpha/auth/enable \
    -X POST -d '{}'
    
# authenticate
token=`curl -s -L http://localhost:2379/v3alpha/auth/authenticate \
    -X POST -d '{ "name":"root", "password":"toor" }' | grep -o '"token[^}]*' | awk  -F '"' '{print $4}'` 

# pass token via header
curl -L http://localhost:2379/v3alpha/kv/put \
     -H "Authorization : $token" \
     -X POST -d '{"key": "Zm9v", "value": "YmFy"}'

https://gist.github.com/hexfusion/461e43f5a850bc63507dc2df2ac27c6a

@hexfusion
Copy link
Contributor Author

@heyitsanthony any idea when this might be released? Thanks,

@heyitsanthony
Copy link
Contributor

@hexfusion 3.3, the minimum for the rc is still a few weeks away

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Development

No branches or pull requests

5 participants