6cd77e9b910a9de43f9a603856dd753998fc6cd4
[sqoop.git] / server / src / main / java / org / apache / sqoop / handler / AuthorizationRequestHandler.java
1 /**
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing, software
13 * distributed under the License is distributed on an "AS IS" BASIS,
14 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 * See the License for the specific language governing permissions and
16 * limitations under the License.
17 */
18 package org.apache.sqoop.handler;
19
20 import org.apache.log4j.Logger;
21 import org.apache.sqoop.audit.AuditLoggerManager;
22 import org.apache.sqoop.common.SqoopException;
23 import org.apache.sqoop.core.SqoopConfiguration;
24 import org.apache.sqoop.error.code.CommonRepositoryError;
25 import org.apache.sqoop.repository.Repository;
26 import org.apache.sqoop.repository.RepositoryManager;
27 import org.apache.sqoop.server.common.ServerError;
28 import org.apache.sqoop.json.*;
29 import org.apache.sqoop.model.MPrincipal;
30 import org.apache.sqoop.model.MPrivilege;
31 import org.apache.sqoop.model.MResource;
32 import org.apache.sqoop.model.MRole;
33 import org.apache.sqoop.security.AuthorizationHandler;
34 import org.apache.sqoop.security.AuthorizationManager;
35 import org.apache.sqoop.security.SecurityConstants;
36 import org.apache.sqoop.security.SecurityError;
37 import org.apache.sqoop.server.RequestContext;
38 import org.apache.sqoop.server.RequestHandler;
39 import org.json.simple.JSONObject;
40
41 import java.io.IOException;
42 import java.util.List;
43
44 public class AuthorizationRequestHandler implements RequestHandler {
45 private static final long serialVersionUID = 1L;
46 /**
47 * enum for representing the actions supported on the authorization
48 */
49 enum Action {
50 AUTHORIZATION("authorization"), //parent url path
51 ROLES("roles"), //first level url path
52 PRINCIPALS("principals"), //first level url path
53 PRIVILEGES("privileges"), //first level url path
54 CREATE("create"), //second level url path
55 GRANT("grant"), //second level url path
56 REVOKE("revoke"); //second level url path
57
58 Action(String name) {
59 this.name = name;
60 }
61
62 String name;
63
64 public static Action fromString(String name) {
65 if (name != null) {
66 for (Action action : Action.values()) {
67 if (name.equalsIgnoreCase(action.name)) {
68 return action;
69 }
70 }
71 }
72 return null;
73 }
74 }
75
76 private static final Logger LOG = Logger.getLogger(AuthorizationRequestHandler.class);
77
78 public AuthorizationRequestHandler() {
79 LOG.info("AuthorizationRequestHandler initialized");
80 }
81
82 @Override
83 public JsonBean handleEvent(RequestContext ctx) {
84 Action action = Action.fromString(ctx.getLastURLElement());
85 String url = ctx.getRequest().getRequestURI();
86 switch (ctx.getMethod()) {
87 case GET:
88 switch (action) {
89 case ROLES: //url: /authorization/roles
90 return getRoles(ctx);
91 case PRINCIPALS: //url: /authorization/principals
92 return getPrincipal(ctx);
93 case PRIVILEGES: //url: /authorization/privileges
94 return getPrivilege(ctx);
95 default:
96 throw new SqoopException(ServerError.SERVER_0003, "Invalid action in url" + url);
97 }
98 case POST:
99 switch (action) {
100 case CREATE: //url: /authorization/roles/create
101 return createRole(ctx);
102 default:
103 throw new SqoopException(ServerError.SERVER_0003, "Invalid action in url" + url);
104 }
105 case PUT:
106 String[] urlElements = ctx.getUrlElements();
107 Action first_level_action = Action.fromString(urlElements[urlElements.length - 2]);
108 switch (first_level_action) {
109 case ROLES:
110 switch (action) {
111 case GRANT: //url: /authorization/roles/grant
112 return grantRevokeRole(ctx, true);
113 case REVOKE: //url: /authorization/roles/revoke
114 return grantRevokeRole(ctx, false);
115 default:
116 throw new SqoopException(ServerError.SERVER_0003, "Invalid action in url" + url);
117 }
118 case PRIVILEGES:
119 switch (action) {
120 case GRANT: //url: /authorization/privileges/grant
121 return grantRevokePrivilege(ctx, true);
122 case REVOKE: //url: /authorization/privileges/revoke
123 return grantRevokePrivilege(ctx, false);
124 default:
125 throw new SqoopException(ServerError.SERVER_0003, "Invalid action in url" + url);
126 }
127 default:
128 throw new SqoopException(ServerError.SERVER_0003, "Invalid action in url" + url);
129 }
130 case DELETE: //url: /authorization/roles/{role_name}
131 return dropRole(ctx);
132 default:
133 throw new SqoopException(ServerError.SERVER_0003, "Invalid action in url" + url);
134 }
135 }
136
137 private JsonBean getRoles(RequestContext ctx) {
138 AuthorizationHandler handler = AuthorizationManager.getInstance().getAuthorizationHandler();
139 AuditLoggerManager manager = AuditLoggerManager.getInstance();
140 String principal_name = ctx.getParameterValue(PRINCIPAL_NAME_QUERY_PARAM);
141 String principal_type = ctx.getParameterValue(PRINCIPAL_TYPE_QUERY_PARAM);
142
143 if (principal_name != null && principal_type != null) {
144 // get roles by principal
145 MPrincipal principal = new MPrincipal(principal_name, principal_type);
146 manager.logAuditEvent(ctx.getUserName(),
147 ctx.getRequest().getRemoteAddr(), "get", "roles by principal", principal.toString());
148 return new RoleBean(handler.getRolesByPrincipal(principal));
149 } else {
150 // get all roles in the system
151 manager.logAuditEvent(ctx.getUserName(),
152 ctx.getRequest().getRemoteAddr(), "get", "roles", "all");
153 return new RoleBean(handler.getAllRoles());
154 }
155 }
156
157 private JsonBean getPrincipal(RequestContext ctx) {
158 AuthorizationHandler handler = AuthorizationManager.getInstance().getAuthorizationHandler();
159 AuditLoggerManager manager = AuditLoggerManager.getInstance();
160 String role_name = ctx.getParameterValue(ROLE_NAME_QUERY_PARAM);
161
162 if (role_name != null) {
163 // get principal by role
164 MRole role = new MRole(role_name);
165 manager.logAuditEvent(ctx.getUserName(),
166 ctx.getRequest().getRemoteAddr(), "get", "principals by role", role.toString());
167 return new PrincipalBean(handler.getPrincipalsByRole(role));
168 } else {
169 throw new SqoopException(SecurityError.AUTH_0012, "Can't get role name");
170 }
171 }
172
173 private void checkResourceExists(MResource resource) {
174 if (resource == null) {
175 return;
176 }
177
178 Boolean resourceExists = false;
179 Repository repository = RepositoryManager.getInstance().getRepository();
180 MResource.TYPE type = MResource.TYPE.valueOf(resource.getType());
181
182 if (type == MResource.TYPE.CONNECTOR) {
183 if (repository.findConnector(resource.getName()) != null) {
184 resourceExists = true;
185 }
186 } else if (type == MResource.TYPE.LINK) {
187 if (repository.findLink(resource.getName()) != null) {
188 resourceExists = true;
189 }
190 } else if (type == MResource.TYPE.JOB) {
191 if (repository.findJob(resource.getName()) != null) {
192 resourceExists = true;
193 }
194 } else {
195 // For MResource.Type.SERVER, it must exists
196 resourceExists = true;
197 }
198
199 if (!resourceExists) {
200 throw new SqoopException(CommonRepositoryError.COMMON_0058,
201 "Can't find resource " + resource.toString());
202 }
203 }
204
205 private JsonBean getPrivilege(RequestContext ctx) {
206 AuthorizationHandler handler = AuthorizationManager.getInstance().getAuthorizationHandler();
207 AuditLoggerManager manager = AuditLoggerManager.getInstance();
208 String principal_name = ctx.getParameterValue(PRINCIPAL_NAME_QUERY_PARAM);
209 String principal_type = ctx.getParameterValue(PRINCIPAL_TYPE_QUERY_PARAM);
210 String resource_name = ctx.getParameterValue(RESOURCE_NAME_QUERY_PARAM);
211 String resource_type = ctx.getParameterValue(RESOURCE_TYPE_QUERY_PARAM);
212
213 if (principal_name != null && principal_type != null) {
214 // get privilege by principal
215 MPrincipal principal = new MPrincipal(principal_name, principal_type);
216 MResource resource = null;
217 if (resource_name != null && resource_type != null) {
218 resource = new MResource(resource_name, resource_type);
219 }
220 checkResourceExists(resource);
221 manager.logAuditEvent(ctx.getUserName(),
222 ctx.getRequest().getRemoteAddr(), "get", "privileges by principal", principal.toString());
223 return new PrivilegesBean(handler.getPrivilegesByPrincipal(principal, resource));
224 } else {
225 throw new SqoopException(SecurityError.AUTH_0013, "Can't get principal");
226 }
227 }
228
229 private JsonBean createRole(RequestContext ctx) {
230 AuthorizationHandler handler = AuthorizationManager.getInstance().getAuthorizationHandler();
231 AuditLoggerManager manager = AuditLoggerManager.getInstance();
232
233 RoleBean bean = new RoleBean();
234
235 try {
236 JSONObject json = JSONUtils.parse(ctx.getRequest().getReader());
237 bean.restore(json);
238 } catch (IOException e) {
239 throw new SqoopException(ServerError.SERVER_0003, "Can't read request content", e);
240 }
241
242 // Get role object
243 List<MRole> roles = bean.getRoles();
244
245 if (roles.size() != 1) {
246 throw new SqoopException(ServerError.SERVER_0003, "Expected one role but got " + roles.size());
247 }
248
249 MRole postedRole = roles.get(0);
250
251 manager.logAuditEvent(ctx.getUserName(),
252 ctx.getRequest().getRemoteAddr(), "create", "role", postedRole.toString());
253 handler.createRole(postedRole);
254 return JsonBean.EMPTY_BEAN;
255 }
256
257 private JsonBean grantRevokeRole(RequestContext ctx, boolean isGrant) {
258 AuthorizationHandler handler = AuthorizationManager.getInstance().getAuthorizationHandler();
259 AuditLoggerManager manager = AuditLoggerManager.getInstance();
260
261 RoleBean rolesBean = new RoleBean();
262 PrincipalBean principalsBean = new PrincipalBean();
263
264 try {
265 JSONObject json = JSONUtils.parse(ctx.getRequest().getReader());
266 rolesBean.restore(json);
267 principalsBean.restore(json);
268 } catch (IOException e) {
269 throw new SqoopException(ServerError.SERVER_0003, "Can't read request content", e);
270 }
271
272 // Get role object
273 List<MRole> roles = rolesBean.getRoles();
274 // Get principal object
275 List<MPrincipal> principals = principalsBean.getPrincipals();
276
277 if (isGrant) {
278 manager.logAuditEvent(ctx.getUserName(),
279 ctx.getRequest().getRemoteAddr(), "grant", "role", "principal");
280 handler.grantRole(principals, roles);
281 } else {
282 manager.logAuditEvent(ctx.getUserName(),
283 ctx.getRequest().getRemoteAddr(), "revoke", "role", "principal");
284 handler.revokeRole(principals, roles);
285 }
286 return JsonBean.EMPTY_BEAN;
287 }
288
289 private JsonBean grantRevokePrivilege(RequestContext ctx, boolean isGrant) {
290 AuthorizationHandler handler = AuthorizationManager.getInstance().getAuthorizationHandler();
291 AuditLoggerManager manager = AuditLoggerManager.getInstance();
292
293 PrincipalBean principalsBean = new PrincipalBean();
294 PrivilegesBean privilegesBean = new PrivilegesBean();
295
296 try {
297 JSONObject json = JSONUtils.parse(ctx.getRequest().getReader());
298 principalsBean.restore(json);
299 try {
300 privilegesBean.restore(json);
301 } catch (Exception e) {//Privilege is null, revoke all privileges from principal
302 privilegesBean = null;
303 }
304 } catch (IOException e) {
305 throw new SqoopException(ServerError.SERVER_0003, "Can't read request content", e);
306 }
307
308 // Get principal object
309 List<MPrincipal> principals = principalsBean.getPrincipals();
310 // Get privilege object
311 List<MPrivilege> privileges = privilegesBean == null ? null : privilegesBean.getPrivileges();
312
313 String defaultUser = SqoopConfiguration.getInstance().getContext().getString(
314 SecurityConstants.AUTHENTICATION_DEFAULT_USER,
315 SecurityConstants.AUTHENTICATION_DEFAULT_USER_DEFAULT);
316 for (MPrincipal principal : principals) {
317 if (defaultUser.equals(principal.getName())) {
318 throw new SqoopException(SecurityError.AUTH_0015);
319 }
320 }
321
322 if (privileges != null) {
323 for (MPrivilege privilege : privileges) {
324 checkResourceExists(privilege.getResource());
325 }
326 } else if (isGrant){
327 throw new SqoopException(CommonRepositoryError.COMMON_0058,
328 "Resource can't be null");
329 }
330
331 if (isGrant) {
332 manager.logAuditEvent(ctx.getUserName(),
333 ctx.getRequest().getRemoteAddr(), "grant", "role", "privilege");
334 handler.grantPrivileges(principals, privileges);
335 } else {
336 manager.logAuditEvent(ctx.getUserName(),
337 ctx.getRequest().getRemoteAddr(), "revoke", "role", "privilege");
338 handler.revokePrivileges(principals, privileges);
339 }
340 return JsonBean.EMPTY_BEAN;
341 }
342
343 private JsonBean dropRole(RequestContext ctx) {
344 AuthorizationHandler handler = AuthorizationManager.getInstance().getAuthorizationHandler();
345 AuditLoggerManager manager = AuditLoggerManager.getInstance();
346
347 String[] urlElements = ctx.getUrlElements();
348
349 //wrong URL
350 if (urlElements.length < 2 ||
351 !urlElements[urlElements.length - 2].equals(Action.ROLES.name)) {
352 throw new SqoopException(SecurityError.AUTH_0012, "Can't get role name");
353 }
354
355 String role_name = ctx.getLastURLElement();
356 MRole role = new MRole(role_name);
357 manager.logAuditEvent(ctx.getUserName(),
358 ctx.getRequest().getRemoteAddr(), "delete", "role", role.toString());
359 handler.dropRole(role);
360 return JsonBean.EMPTY_BEAN;
361 }
362 }