1 | /******************************************************************** |
2 | * Copyright (c) 2013 - 2014, Pivotal Inc. |
3 | * All rights reserved. |
4 | * |
5 | * Author: Zhanwei Wang |
6 | ********************************************************************/ |
7 | /******************************************************************** |
8 | * 2014 - |
9 | * open source under Apache License Version 2.0 |
10 | ********************************************************************/ |
11 | /** |
12 | * Licensed to the Apache Software Foundation (ASF) under one |
13 | * or more contributor license agreements. See the NOTICE file |
14 | * distributed with this work for additional information |
15 | * regarding copyright ownership. The ASF licenses this file |
16 | * to you under the Apache License, Version 2.0 (the |
17 | * "License"); you may not use this file except in compliance |
18 | * with the License. You may obtain a copy of the License at |
19 | * |
20 | * http://www.apache.org/licenses/LICENSE-2.0 |
21 | * |
22 | * Unless required by applicable law or agreed to in writing, software |
23 | * distributed under the License is distributed on an "AS IS" BASIS, |
24 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
25 | * See the License for the specific language governing permissions and |
26 | * limitations under the License. |
27 | */ |
28 | #include "Exception.h" |
29 | #include "ExceptionInternal.h" |
30 | #include "Hash.h" |
31 | #include "Token.h" |
32 | #include "WritableUtils.h" |
33 | |
34 | #include <gsasl.h> |
35 | |
36 | using namespace Hdfs::Internal; |
37 | |
38 | namespace Hdfs { |
39 | namespace Internal { |
40 | |
41 | static std::string Base64Encode(const char * input, size_t len) { |
42 | int rc = 0; |
43 | size_t outLen; |
44 | char * output = NULL; |
45 | std::string retval; |
46 | |
47 | if (GSASL_OK != (rc = gsasl_base64_to(input, len, &output, &outLen))) { |
48 | assert(GSASL_MALLOC_ERROR == rc); |
49 | throw std::bad_alloc(); |
50 | } |
51 | |
52 | assert(NULL != output); |
53 | retval = output; |
54 | gsasl_free(output); |
55 | |
56 | for (size_t i = 0 ; i < retval.length(); ++i) { |
57 | switch (retval[i]) { |
58 | case '+': |
59 | retval[i] = '-'; |
60 | break; |
61 | |
62 | case '/': |
63 | retval[i] = '_'; |
64 | break; |
65 | |
66 | case '=': |
67 | retval.resize(i); |
68 | break; |
69 | |
70 | default: |
71 | break; |
72 | } |
73 | } |
74 | |
75 | return retval; |
76 | } |
77 | |
78 | static void Base64Decode(const std::string & urlSafe, |
79 | std::vector<char> & buffer) { |
80 | int retval = 0, append = 0; |
81 | size_t outLen; |
82 | char * output = NULL; |
83 | std::string input = urlSafe; |
84 | |
85 | for (size_t i = 0; i < input.length(); ++i) { |
86 | switch (input[i]) { |
87 | case '-': |
88 | input[i] = '+'; |
89 | break; |
90 | |
91 | case '_': |
92 | input[i] = '/'; |
93 | break; |
94 | |
95 | default: |
96 | break; |
97 | } |
98 | } |
99 | |
100 | while (true) { |
101 | retval = gsasl_base64_from(&input[0], input.length(), &output, &outLen); |
102 | |
103 | if (GSASL_OK != retval) { |
104 | switch (retval) { |
105 | case GSASL_BASE64_ERROR: |
106 | if (append++ < 2) { |
107 | input.append("=" ); |
108 | continue; |
109 | } |
110 | |
111 | throw std::invalid_argument( |
112 | "invalid input of gsasl_base64_from" ); |
113 | |
114 | case GSASL_MALLOC_ERROR: |
115 | throw std::bad_alloc(); |
116 | |
117 | default: |
118 | assert( |
119 | false |
120 | && "unexpected return value from gsasl_base64_from" ); |
121 | } |
122 | } |
123 | |
124 | break; |
125 | } |
126 | |
127 | assert(outLen >= 0); |
128 | buffer.resize(outLen); |
129 | memcpy(&buffer[0], output, outLen); |
130 | gsasl_free(output); |
131 | } |
132 | |
133 | std::string Token::toString() const { |
134 | try { |
135 | size_t len = 0; |
136 | std::vector<char> buffer(1024); |
137 | WritableUtils out(&buffer[0], buffer.size()); |
138 | len += out.WriteInt32(identifier.size()); |
139 | len += out.WriteRaw(&identifier[0], identifier.size()); |
140 | len += out.WriteInt32(password.size()); |
141 | len += out.WriteRaw(&password[0], password.size()); |
142 | len += out.WriteText(kind); |
143 | len += out.WriteText(service); |
144 | return Base64Encode(&buffer[0], len); |
145 | } catch (...) { |
146 | NESTED_THROW(HdfsIOException, "cannot convert token to string" ); |
147 | } |
148 | } |
149 | |
150 | Token & Token::fromString(const std::string & str) { |
151 | int32_t len; |
152 | |
153 | try { |
154 | std::vector<char> buffer; |
155 | Base64Decode(str, buffer); |
156 | WritableUtils in(&buffer[0], buffer.size()); |
157 | len = in.ReadInt32(); |
158 | identifier.resize(len); |
159 | in.ReadRaw(&identifier[0], len); |
160 | len = in.ReadInt32(); |
161 | password.resize(len); |
162 | in.ReadRaw(&password[0], len); |
163 | kind = in.ReadText(); |
164 | service = in.ReadText(); |
165 | return *this; |
166 | } catch (...) { |
167 | NESTED_THROW(HdfsInvalidBlockToken, |
168 | "cannot construct a token from the string" ); |
169 | } |
170 | } |
171 | |
172 | size_t Token::hash_value() const { |
173 | size_t values[] = { StringHasher(identifier), StringHasher(password), |
174 | StringHasher(kind), StringHasher(service) |
175 | }; |
176 | return CombineHasher(values, sizeof(values) / sizeof(values[0])); |
177 | } |
178 | |
179 | } |
180 | } |
181 | |