{"action":"created","issue":{"url":"https://api.github.com/repos/apache/flink/issues/2425","repository_url":"https://api.github.com/repos/apache/flink","labels_url":"https://api.github.com/repos/apache/flink/issues/2425/labels{/name}","comments_url":"https://api.github.com/repos/apache/flink/issues/2425/comments","events_url":"https://api.github.com/repos/apache/flink/issues/2425/events","html_url":"https://github.com/apache/flink/pull/2425","id":173523427,"number":2425,"title":"FLINK-3930 Added shared secret based authorization for Flink service …","user":{"login":"vijikarthi","id":5560671,"avatar_url":"https://avatars.githubusercontent.com/u/5560671?v=3","gravatar_id":"","url":"https://api.github.com/users/vijikarthi","html_url":"https://github.com/vijikarthi","followers_url":"https://api.github.com/users/vijikarthi/followers","following_url":"https://api.github.com/users/vijikarthi/following{/other_user}","gists_url":"https://api.github.com/users/vijikarthi/gists{/gist_id}","starred_url":"https://api.github.com/users/vijikarthi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vijikarthi/subscriptions","organizations_url":"https://api.github.com/users/vijikarthi/orgs","repos_url":"https://api.github.com/users/vijikarthi/repos","events_url":"https://api.github.com/users/vijikarthi/events{/privacy}","received_events_url":"https://api.github.com/users/vijikarthi/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"assignees":[],"milestone":null,"comments":29,"created_at":"2016-08-26T19:14:04Z","updated_at":"2016-11-07T00:45:36Z","closed_at":null,"pull_request":{"url":"https://api.github.com/repos/apache/flink/pulls/2425","html_url":"https://github.com/apache/flink/pull/2425","diff_url":"https://github.com/apache/flink/pull/2425.diff","patch_url":"https://github.com/apache/flink/pull/2425.patch"},"body":"This PR addresses FLINK-3930 requirements. It enables shared secret based secure cookie authorization for the following components\n- Akka layer\n- Blob Service\n- Web UI\n\nSecure cookie authentication can be enabled by providing below configurations to Flink configuration file.\n- `security.enabled`: A boolean value (true|false) indicating security is enabled or not.\n- `security.cookie` : Secure cookie value to be used for authentication. For standalone deployment mode, the secure cookie value is mandatory when security is enabled but for the Yarn mode it is optional (auto-generated if not provided).\n\nAlternatively, secure cookie value can be provided through Flink/Yarn CLI using \"-k\" or \"--cookie\" parameter option.\n\nThe web runtime module prompts for secure cookie using standard basic HTTP authentication mechanism, where the user id field is a noop and the password field will be used to capture the secure cookie. \n"},"comment":{"url":"https://api.github.com/repos/apache/flink/issues/comments/258724575","html_url":"https://github.com/apache/flink/pull/2425#issuecomment-258724575","issue_url":"https://api.github.com/repos/apache/flink/issues/2425","id":258724575,"user":{"login":"vijikarthi","id":5560671,"avatar_url":"https://avatars.githubusercontent.com/u/5560671?v=3","gravatar_id":"","url":"https://api.github.com/users/vijikarthi","html_url":"https://github.com/vijikarthi","followers_url":"https://api.github.com/users/vijikarthi/followers","following_url":"https://api.github.com/users/vijikarthi/following{/other_user}","gists_url":"https://api.github.com/users/vijikarthi/gists{/gist_id}","starred_url":"https://api.github.com/users/vijikarthi/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/vijikarthi/subscriptions","organizations_url":"https://api.github.com/users/vijikarthi/orgs","repos_url":"https://api.github.com/users/vijikarthi/repos","events_url":"https://api.github.com/users/vijikarthi/events{/privacy}","received_events_url":"https://api.github.com/users/vijikarthi/received_events","type":"User","site_admin":false},"created_at":"2016-11-07T00:45:36Z","updated_at":"2016-11-07T00:45:36Z","body":">\r\nThe cookie is added to every single message/buffer that is transferred. That is too much - securing the integrity of the stream is responsibility of the encryption layer. The cookie should be added to requests messages that establish connections only.\r\n\r\nI will change the code to address cookie handling right after the SSL handshake using a new handler and drop the cookie passing for every messages. The handler will be added to the pipeline of both `NettyClient` and `NettyServer`. Client will send the cookie when the channel becomes active and the server will validate and keep track of the clients that are authorized. \r\n\r\nHere is the pseudo-code for Client and Server handlers. Please take a look and let me know if you are okay with this approach and I will modify the code.\r\n\r\n---\r\n\tpublic static class ClientCookieHandler extends ChannelInboundHandlerAdapter {\r\n\r\n\t\tprivate final String secureCookie;\r\n\r\n\t\tfinal Charset DEFAULT_CHARSET = Charset.forName(\"utf-8\");\r\n\r\n\t\tpublic ClientCookieHandler(String secureCookie) {\r\n\t\t\tthis.secureCookie = secureCookie;\r\n\t\t}\r\n\r\n\r\n\t\t@Override\r\n\t\tpublic void channelActive(ChannelHandlerContext ctx) throws Exception {\r\n\t\t\tsuper.channelActive(ctx);\r\n\r\n\t\t\tif(this.secureCookie != null && this.secureCookie.length() != 0) {\r\n\t\t\t\tfinal ByteBuf buffer = Unpooled.buffer(4 + this.secureCookie.getBytes(DEFAULT_CHARSET).length);\r\n\t\t\t\tbuffer.writeInt(secureCookie.getBytes(DEFAULT_CHARSET).length);\r\n\t\t\t\tbuffer.writeBytes(secureCookie.getBytes(DEFAULT_CHARSET));\r\n\t\t\t\tctx.writeAndFlush(buffer);\r\n\t\t\t}\r\n\t\t}\r\n\t}\r\n\r\n\tpublic static class ServerCookieDecoder extends MessageToMessageDecoder<ByteBuf> {\r\n\r\n\t\tprivate final String secureCookie;\r\n\r\n\t\tprivate final List<Channel> channelList = new ArrayList<>();\r\n\r\n\t\tprivate final Charset DEFAULT_CHARSET = Charset.forName(\"utf-8\");\r\n\r\n\t       public ServerCookieDecoder(String secureCookie) {\r\n\t\t\tthis.secureCookie = secureCookie;\r\n\t\t}\r\n\r\n\t\t@Override\r\n\t\tprotected void decode(ChannelHandlerContext ctx, ByteBuf msg, List<Object> out) throws Exception {\r\n\r\n\t\t\tif(secureCookie == null || secureCookie.length() == 0) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\tif(channelList.contains(ctx.channel())) {\r\n\t\t\t\treturn;\r\n\t\t\t}\r\n\r\n\t\t\t//read cookie based on the cookie length passed\r\n\t\t\tint cookieLength = msg.readInt();\r\n\t\t\tif(cookieLength != secureCookie.getBytes(DEFAULT_CHARSET).length) {\r\n\t\t\t\tString message = \"Cookie length does not match with source cookie. Invalid secure cookie passed.\";\r\n\t\t\t\tthrow new IllegalStateException(message);\r\n\t\t\t}\r\n\r\n\t\t\t//read only if cookie length is greater than zero\r\n\t\t\tif(cookieLength > 0) {\r\n\r\n\t\t\t\tfinal byte[] buffer = new byte[secureCookie.getBytes(DEFAULT_CHARSET).length];\r\n\t\t\t\tmsg.readBytes(buffer, 0, cookieLength);\r\n\r\n\t\t\t\tif(!Arrays.equals(secureCookie.getBytes(DEFAULT_CHARSET), buffer)) {\r\n\t\t\t\t\tLOG.error(\"Secure cookie from the client is not matching with the server's identity\");\r\n\t\t\t\t\tthrow new IllegalStateException(\"Invalid secure cookie passed.\");\r\n\t\t\t\t}\r\n\r\n\t\t\t\tLOG.info(\"Secure cookie validation passed\");\r\n\r\n\t\t\t\tchannelList.add(ctx.channel());\r\n\t\t\t}\r\n\r\n\t\t}\r\n\t}\r\n--- "}}
{"actor":{"display_login":"vijikarthi"}}