001package org.apache.archiva.redback.role; 002 003/* 004 * Licensed to the Apache Software Foundation (ASF) under one 005 * or more contributor license agreements. See the NOTICE file 006 * distributed with this work for additional information 007 * regarding copyright ownership. The ASF licenses this file 008 * to you under the Apache License, Version 2.0 (the 009 * "License"); you may not use this file except in compliance 010 * with the License. You may obtain a copy of the License at 011 * 012 * http://www.apache.org/licenses/LICENSE-2.0 013 * 014 * Unless required by applicable law or agreed to in writing, 015 * software distributed under the License is distributed on an 016 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 017 * KIND, either express or implied. See the License for the 018 * specific language governing permissions and limitations 019 * under the License. 020 */ 021 022import org.apache.archiva.redback.rbac.RBACManager; 023import org.apache.archiva.redback.rbac.RbacManagerException; 024import org.apache.archiva.redback.rbac.RbacObjectNotFoundException; 025import org.apache.archiva.redback.rbac.Role; 026import org.apache.archiva.redback.rbac.UserAssignment; 027import org.apache.archiva.redback.role.model.ModelApplication; 028import org.apache.archiva.redback.role.model.ModelRole; 029import org.apache.archiva.redback.role.model.ModelTemplate; 030import org.apache.archiva.redback.role.model.RedbackRoleModel; 031import org.apache.archiva.redback.role.model.io.stax.RedbackRoleModelStaxReader; 032import org.apache.archiva.redback.role.processor.RoleModelProcessor; 033import org.apache.commons.io.IOUtils; 034import org.apache.archiva.redback.rbac.Resource; 035import org.apache.archiva.redback.role.template.RoleTemplateProcessor; 036import org.apache.archiva.redback.role.util.RoleModelUtils; 037import org.apache.archiva.redback.role.validator.RoleModelValidator; 038import org.apache.commons.lang3.SystemUtils; 039import org.apache.commons.lang3.time.StopWatch; 040import org.slf4j.Logger; 041import org.slf4j.LoggerFactory; 042import org.springframework.stereotype.Service; 043 044import javax.annotation.PostConstruct; 045import javax.inject.Inject; 046import javax.inject.Named; 047import javax.xml.stream.XMLStreamException; 048import java.io.IOException; 049import java.io.InputStreamReader; 050import java.net.MalformedURLException; 051import java.net.URL; 052import java.util.Arrays; 053import java.util.Enumeration; 054import java.util.HashMap; 055import java.util.List; 056import java.util.Map; 057 058/** 059 * RoleProfileManager: 060 * 061 * @author: Jesse McConnell 062 */ 063@Service("roleManager") 064public class DefaultRoleManager 065 implements RoleManager 066{ 067 private Logger log = LoggerFactory.getLogger( DefaultRoleManager.class ); 068 069 /** 070 * the blessed model that has been validated as complete 071 */ 072 private RedbackRoleModel blessedModel; 073 074 /** 075 * the merged model that can be validated as complete 076 */ 077 private RedbackRoleModel unblessedModel; 078 079 /** 080 * a map of the resources, and the model that they loaded 081 */ 082 private Map<String, ModelApplication> knownResources = new HashMap<String, ModelApplication>(); 083 084 @Inject 085 @Named(value = "roleModelValidator") 086 private RoleModelValidator modelValidator; 087 088 @Inject 089 @Named(value = "roleModelProcessor") 090 private RoleModelProcessor modelProcessor; 091 092 @Inject 093 @Named(value = "roleTemplateProcessor") 094 private RoleTemplateProcessor templateProcessor; 095 096 @Inject 097 @Named(value = "rbacManager#default") 098 private RBACManager rbacManager; 099 100 101 @Override 102 public void loadRoleModel( URL resource ) 103 throws RoleManagerException 104 { 105 RedbackRoleModelStaxReader reader = new RedbackRoleModelStaxReader(); 106 107 try(InputStreamReader inputStreamReader = new InputStreamReader( resource.openStream() )) 108 { 109 110 RedbackRoleModel roleModel = reader.read( inputStreamReader ); 111 112 for ( ModelApplication app : roleModel.getApplications() ) 113 { 114 if ( !knownResources.containsKey( app.getId() ) ) 115 { 116 log.info( "loading {}", app.getId() ); 117 loadApplication( app ); 118 } 119 } 120 } 121 catch ( MalformedURLException e ) 122 { 123 throw new RoleManagerException( "error locating redback profile", e ); 124 } 125 catch ( IOException e ) 126 { 127 throw new RoleManagerException( "error reading redback profile", e ); 128 } 129 catch ( XMLStreamException e ) 130 { 131 throw new RoleManagerException( "error parsing redback profile", e ); 132 } 133 } 134 135 @Override 136 public void loadRoleModel( RedbackRoleModel roleModel ) 137 throws RoleManagerException 138 { 139 for ( ModelApplication app : roleModel.getApplications() ) 140 { 141 if ( !knownResources.containsKey( app.getId() ) ) 142 { 143 loadApplication( app ); 144 } 145 } 146 147 } 148 149 public void loadApplication( ModelApplication app ) 150 throws RoleManagerException 151 { 152 if ( unblessedModel == null ) 153 { 154 unblessedModel = new RedbackRoleModel(); 155 } 156 157 unblessedModel.addApplication( app ); 158 159 if ( modelValidator.validate( unblessedModel ) ) 160 { 161 blessedModel = unblessedModel; 162 } 163 else 164 { 165 StringBuilder stringBuilder = new StringBuilder( "Role Model Validation Errors:" ); 166 167 for ( String error : modelValidator.getValidationErrors() ) 168 { 169 stringBuilder.append( error ).append( SystemUtils.LINE_SEPARATOR ); 170 } 171 172 log.error( stringBuilder.toString() ); 173 174 throw new RoleManagerException( 175 "Role Model Validation Error " + SystemUtils.LINE_SEPARATOR + stringBuilder.toString() ); 176 } 177 178 modelProcessor.process( blessedModel ); 179 180 knownResources.put( app.getId(), app ); 181 } 182 183 /** 184 * create a role for the given roleName using the resource passed in for 185 * resolving the ${resource} expression 186 */ 187 @Override 188 public String createTemplatedRole( String templateId, String resource ) 189 throws RoleManagerException 190 { 191 return templateProcessor.create( blessedModel, templateId, resource ); 192 } 193 194 /** 195 * remove the role corresponding to the role using the resource passed in for resolving the 196 * ${resource} expression 197 */ 198 @Override 199 public void removeTemplatedRole( String templateId, String resource ) 200 throws RoleManagerException 201 { 202 String roleId = templateProcessor.getRoleId( templateId, resource ); 203 try 204 { 205 Role role = rbacManager.getRoleById( roleId ); 206 207 for ( UserAssignment assignment : rbacManager.getUserAssignmentsForRoles( 208 Arrays.asList( role.getId() ) ) ) 209 { 210 assignment.removeRoleId( role ); 211 rbacManager.saveUserAssignment( assignment ); 212 } 213 214 } catch ( RbacObjectNotFoundException e) { 215 throw new RoleNotFoundException( e.getMessage( ), e ); 216 } 217 catch ( RbacManagerException e ) 218 { 219 throw new RoleManagerException( "Unable to remove role", e ); 220 } 221 222 templateProcessor.remove( blessedModel, templateId, resource ); 223 } 224 225 /** 226 * update the role from templateId from oldResource to newResource 227 * 228 * NOTE: this requires removal and creation of the role since the jdo store does not tolerate renaming 229 * because of the use of the name as an identifier 230 */ 231 @Override 232 public String moveTemplatedRole( String templateId, String oldResource, String newResource ) 233 throws RoleManagerException 234 { 235 // make the new role 236 String roleId = templateProcessor.create( blessedModel, templateId, newResource ); 237 238 ModelTemplate template = RoleModelUtils.getModelTemplate( blessedModel, templateId ); 239 240 String oldRoleName = template.getNamePrefix() + template.getDelimiter() + oldResource; 241 String newRoleName = template.getNamePrefix() + template.getDelimiter() + newResource; 242 243 String oldRoleId = RoleModelUtils.getRoleId( templateId, oldResource ); 244 String newRoleId = RoleModelUtils.getRoleId( templateId, newResource ); 245 246 try 247 { 248 Role role = rbacManager.getRole( oldRoleName ); 249 250 // remove the user assignments 251 for ( UserAssignment assignment : rbacManager.getUserAssignmentsForRoles( 252 Arrays.asList( role.getId() ) ) ) 253 { 254 assignment.removeRoleId( oldRoleId ); 255 assignment.addRoleId( newRoleId ); 256 rbacManager.saveUserAssignment( assignment ); 257 } 258 } 259 catch ( RbacManagerException e ) 260 { 261 throw new RoleManagerException( "unable to update role", e ); 262 } 263 264 templateProcessor.remove( blessedModel, templateId, oldResource ); 265 return roleId; 266 } 267 268 @Override 269 public void assignRole( String roleId, String principal ) 270 throws RoleManagerException 271 { 272 try 273 { 274 rbacManager.getRoleById( roleId ); 275 } 276 catch ( RbacObjectNotFoundException e ) { 277 throw new RoleNotFoundException( e.getMessage(), e ); 278 } 279 catch ( RbacManagerException e ) 280 { 281 throw new RoleManagerException( e.getMessage( ), e ); 282 } 283 try 284 { 285 UserAssignment userAssignment; 286 287 if ( rbacManager.userAssignmentExists( principal ) ) 288 { 289 userAssignment = rbacManager.getUserAssignment( principal ); 290 } 291 else 292 { 293 userAssignment = rbacManager.createUserAssignment( principal ); 294 } 295 296 userAssignment.addRoleId( roleId ); 297 rbacManager.saveUserAssignment( userAssignment ); 298 } 299 catch ( RbacManagerException e ) 300 { 301 throw new RoleManagerException( "Unable to assign role: unable to manage user assignment", e ); 302 } 303 } 304 305 @Override 306 public void assignRoleByName( String roleName, String principal ) 307 throws RoleManagerException 308 { 309 try 310 { 311 Role role = rbacManager.getRole( roleName ); 312 UserAssignment userAssignment; 313 314 if ( rbacManager.userAssignmentExists( principal ) ) 315 { 316 userAssignment = rbacManager.getUserAssignment( principal ); 317 } 318 else 319 { 320 userAssignment = rbacManager.createUserAssignment( principal ); 321 } 322 323 if ( !rbacManager.roleExists( roleName ) ) 324 { 325 throw new RoleManagerException( "Unable to assign role: " + roleName + " does not exist." ); 326 } 327 328 userAssignment.addRoleId( role.getId() ); 329 rbacManager.saveUserAssignment( userAssignment ); 330 } 331 catch ( RbacManagerException e ) 332 { 333 throw new RoleManagerException( "Unable to assign role: unable to manage user assignment", e ); 334 } 335 } 336 337 @Override 338 public void assignTemplatedRole( String templateId, String resource, String principal ) 339 throws RoleManagerException 340 { 341 ModelTemplate modelTemplate = RoleModelUtils.getModelTemplate( blessedModel, templateId ); 342 343 if ( modelTemplate == null ) 344 { 345 throw new RoleNotFoundException( "Unable to assign role: " + templateId + " does not exist." ); 346 } 347 try 348 { 349 if ( !rbacManager.resourceExists( resource ) ) 350 { 351 Resource newResource = rbacManager.createResource( resource ); 352 rbacManager.saveResource( newResource ); 353 } 354 355 UserAssignment userAssignment; 356 357 if ( rbacManager.userAssignmentExists( principal ) ) 358 { 359 userAssignment = rbacManager.getUserAssignment( principal ); 360 } 361 else 362 { 363 userAssignment = rbacManager.createUserAssignment( principal ); 364 } 365 366 userAssignment.addRoleId( RoleModelUtils.getRoleId( modelTemplate.getId(), resource ) ); 367 rbacManager.saveUserAssignment( userAssignment ); 368 } 369 catch ( RbacManagerException e ) 370 { 371 throw new RoleManagerException( "Unable to assign role: unable to manage user assignment", e ); 372 } 373 } 374 375 @Override 376 public void unassignRole( String roleId, String principal ) 377 throws RoleManagerException 378 { 379 380 try 381 { 382 rbacManager.getRoleById( roleId ); 383 UserAssignment userAssignment; 384 385 if ( rbacManager.userAssignmentExists( principal ) ) 386 { 387 userAssignment = rbacManager.getUserAssignment( principal ); 388 } 389 else 390 { 391 throw new RoleManagerException( 392 "UserAssignment for principal " + principal + "does not exist, can't unassign role." ); 393 } 394 395 userAssignment.removeRoleId( roleId ); 396 rbacManager.saveUserAssignment( userAssignment ); 397 } 398 catch (RoleNotFoundException e) { 399 throw new RoleNotFoundException( "Unable to unassign role: " + roleId + " does not exist." ); 400 } 401 catch ( RbacManagerException e ) 402 { 403 throw new RoleManagerException( "Unable to unassign role: unable to manage user assignment", e ); 404 } 405 } 406 407 @Override 408 public void unassignRoleByName( String roleName, String principal ) 409 throws RoleManagerException 410 { 411 try 412 { 413 UserAssignment userAssignment; 414 415 if ( rbacManager.userAssignmentExists( principal ) ) 416 { 417 userAssignment = rbacManager.getUserAssignment( principal ); 418 } 419 else 420 { 421 throw new RoleManagerException( 422 "UserAssignment for principal " + principal + "does not exist, can't unassign role." ); 423 } 424 425 if ( !rbacManager.roleExists( roleName ) ) 426 { 427 throw new RoleManagerException( "Unable to unassign role: " + roleName + " does not exist." ); 428 } 429 430 Role rbacRole = rbacManager.getRole( roleName ); 431 userAssignment.removeRoleId( rbacRole.getId() ); 432 rbacManager.saveUserAssignment( userAssignment ); 433 } 434 catch ( RbacManagerException e ) 435 { 436 throw new RoleManagerException( "Unable to unassign role: unable to manage user assignment", e ); 437 } 438 } 439 440 @Override 441 public boolean roleExists( String roleId ) 442 throws RoleManagerException 443 { 444 ModelRole modelRole = RoleModelUtils.getModelRole( blessedModel, roleId ); 445 446 if ( modelRole == null ) 447 { 448 return false; 449 } 450 else 451 { 452 try 453 { 454 if ( rbacManager.roleExists( modelRole.getName() ) ) 455 { 456 return true; 457 } 458 else 459 { 460 // perhaps try and reload the model here? 461 throw new RoleManagerException( "breakdown in role management, role '" + modelRole.getName() 462 + "' exists in configuration but was not created in underlying store" ); 463 } 464 } 465 catch ( RbacManagerException e ) 466 { 467 throw new RoleManagerException( e.getMessage(), e ); 468 } 469 } 470 } 471 472 @Override 473 public boolean templatedRoleExists( String templateId, String resource ) 474 throws RoleManagerException 475 { 476 ModelTemplate modelTemplate = RoleModelUtils.getModelTemplate( blessedModel, templateId ); 477 478 // template not existing is valid to check, it will throw exception on trying to create 479 if ( modelTemplate == null ) 480 { 481 return false; 482 } 483 else 484 { 485 try 486 { 487 if ( rbacManager.roleExists( modelTemplate.getNamePrefix() + modelTemplate.getDelimiter() + resource ) ) 488 { 489 return true; 490 } 491 else 492 { 493 return false; 494 } 495 } 496 catch ( RbacManagerException e ) 497 { 498 throw new RoleManagerException( e.getMessage(), e ); 499 } 500 } 501 } 502 503 @Override 504 @PostConstruct 505 public void initialize() 506 { 507 508 knownResources = new HashMap<String, ModelApplication>(); 509 this.unblessedModel = new RedbackRoleModel(); 510 StopWatch stopWatch = new StopWatch(); 511 stopWatch.start(); 512 513 try 514 { 515 URL baseResource = RoleManager.class.getResource( "/META-INF/redback/redback-core.xml" ); 516 517 if ( baseResource == null ) 518 { 519 throw new RuntimeException( "unable to initialize role manager, missing redback-core.xml" ); 520 } 521 522 loadRoleModel( baseResource ); 523 524 Enumeration<URL> enumerator = 525 RoleManager.class.getClassLoader().getResources( "META-INF/redback/redback.xml" ); 526 527 while ( enumerator.hasMoreElements() ) 528 { 529 URL redbackResource = enumerator.nextElement(); 530 531 loadRoleModel( redbackResource ); 532 } 533 } 534 catch ( RoleManagerException e ) 535 { 536 throw new RuntimeException( "unable to initialize RoleManager", e ); 537 } 538 catch ( IOException e ) 539 { 540 throw new RuntimeException( "unable to initialize RoleManager, problem with redback.xml loading", e ); 541 } 542 543 stopWatch.stop(); 544 log.info( "DefaultRoleManager initialize time {}", stopWatch.getTime() ); 545 } 546 547 @Override 548 public RedbackRoleModel getModel() 549 { 550 return blessedModel; 551 } 552 553 @Override 554 public void verifyTemplatedRole( String templateId, String resource ) 555 throws RoleManagerException 556 { 557 // create also serves as update 558 templateProcessor.create( blessedModel, templateId, resource ); 559 } 560 561 public RedbackRoleModel getBlessedModel() 562 { 563 return blessedModel; 564 } 565 566 public void setBlessedModel( RedbackRoleModel blessedModel ) 567 { 568 this.blessedModel = blessedModel; 569 } 570 571 public RedbackRoleModel getUnblessedModel() 572 { 573 return unblessedModel; 574 } 575 576 public void setUnblessedModel( RedbackRoleModel unblessedModel ) 577 { 578 this.unblessedModel = unblessedModel; 579 } 580 581 public Map<String, ModelApplication> getKnownResources() 582 { 583 return knownResources; 584 } 585 586 public void setKnownResources( Map<String, ModelApplication> knownResources ) 587 { 588 this.knownResources = knownResources; 589 } 590 591 public RoleModelValidator getModelValidator() 592 { 593 return modelValidator; 594 } 595 596 public void setModelValidator( RoleModelValidator modelValidator ) 597 { 598 this.modelValidator = modelValidator; 599 } 600 601 public RoleModelProcessor getModelProcessor() 602 { 603 return modelProcessor; 604 } 605 606 public void setModelProcessor( RoleModelProcessor modelProcessor ) 607 { 608 this.modelProcessor = modelProcessor; 609 } 610 611 public RoleTemplateProcessor getTemplateProcessor() 612 { 613 return templateProcessor; 614 } 615 616 public void setTemplateProcessor( RoleTemplateProcessor templateProcessor ) 617 { 618 this.templateProcessor = templateProcessor; 619 } 620 621 public RBACManager getRbacManager() 622 { 623 return rbacManager; 624 } 625 626 public void setRbacManager( RBACManager rbacManager ) 627 { 628 this.rbacManager = rbacManager; 629 } 630}