Skip to content

using authorization stacks instead of a list #1525

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

Merged
merged 7 commits into from
Apr 28, 2017

Conversation

tulinkry
Copy link
Contributor

@tulinkry tulinkry commented Apr 10, 2017

  1. Plugin stack

    This change is to introduce the ability to a plugin stack to be a substack of another plugin stack with similar attributes as the plugins have (1):

    • required
    • requisite
    • sufficient

    The substack can contain an arbitrary number of

    • other stacks
    • plugin classes

    The meaning of the three keywords in (1) is not changed and is extended for the entire stacks as well.

    There is a default required top level stack for the application with a name "default stack"

  2. Plugin parameters

    Another friendliness is that the plugin can now accept an arbitrary parameter included in java Map object. This parameters can be configured in configuration. The parameters can be also used for the entire stack and then it is merged with the plugin specific parameters (the plugin overwrites the conflicts).

    However note that this is BC break as the IAuthorizationInterface has changed slightly.

A configuration example can be this configuration with:

  • two standalone plugins (SamplePlugin, RequisitePlugin)
  • a required substack
    • containing two other plugins
  <void property="pluginStack">
   <void method="add">
    <object class="org.opensolaris.opengrok.authorization.AuthorizationPlugin">
     <void property="name">
      <string>SamplePlugin</string>
     </void>
     <void property="role">
      <string>SUFFICIENT</string>
     </void>
    </object>
   </void>
   <void method="add">
    <object class="org.opensolaris.opengrok.authorization.AuthorizationPlugin">
     <void property="name">
      <string>tulinkry.my.RequisitePlugin</string>
     </void>
     <void property="role">
      <string>REQUIRED</string>
     </void>
     <void property="setup">
		<void method="put">
			<string>config</string>
			<string>/home/ktulinge/my.xml</string>
		</void>
		<void method="put">
			<string>group</string>
			<object idref="group"/>
		</void>
     </void>
    </object>
   </void>
   <void method="add">
    <object class="org.opensolaris.opengrok.authorization.AuthorizationStack">
     <void property="name">
      <string>stack for group 1</string>
     </void>
     <void property="role">
      <string>REQUIRED</string>
     </void>
     <void method="add">
		<object class="org.opensolaris.opengrok.authorization.AuthorizationPlugin">
		 <void property="name">
		  <string>org.opensolaris.opengrok.authorization.plugins.GroupPlugin</string>
		 </void>
		 <void property="role">
		  <string>SUFFICIENT</string>
		 </void>
		 <void property="setup">
		 	<void method="put">
		 	  <string>groups</string>
              <array class="java.lang.String" length="2">
               <void index="0">
                 <string>1</string>
               </void>
               <void index="1">
                 <string>2</string>
               </void>
              </array>
		 	</void>
         </void>
		</object>
     </void>
     <void method="add">
		<object class="org.opensolaris.opengrok.authorization.AuthorizationPlugin">
		 <void property="name">
		  <string>Plugin</string>
		 </void>
		 <void property="role">
		  <string>REQUIRED</string>
		 </void>
		</object>
     </void>
    </object>
   </void>
  </void>

Also note this parts which is how you can set the parameters to the plugin class - property setup which is a Map.

  <void property="groups">
   <void method="add">
    <object class="org.opensolaris.opengrok.configuration.Group"  id="group">
     <void property="name">
      <string>3</string>
     </void>
     <void property="pattern">
      <string>.*\([456]th copy\)</string>
     </void>
    </object>
   </void>
  </void>

  <!-- group with id="group" declared above and the reference can be used later in this file -->

   <void method="add">
    <object class="org.opensolaris.opengrok.authorization.AuthorizationPlugin">
     <void property="name">
      <string>tulinkry.my.RequisitePlugin</string>
     </void>
     <void property="role">
      <string>REQUIRED</string>
     </void>
     <void property="setup">
		<void method="put">
			<string>config</string> <!-- PARAMETER KEY -->
			<string>/home/ktulinge/my.xml</string> <!-- PARAMETER VALUE -->
		</void>
		<void method="put">
			<string>group</string> <!-- PARAMETER KEY -->
			<object idref="group"/> <!-- PARAMETER VALUE => here a group declared in this configuration before this statement -->
		</void>
     </void>
    </object>
   </void>

@tulinkry tulinkry self-assigned this Apr 10, 2017
@@ -0,0 +1,95 @@
/*
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is refactored from the AuthorizationCheck.java class

@@ -1,155 +0,0 @@
/*
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactored to:

  • AuthorizationEntity.java
  • AuthControlFlag.java

public class AuthorizationFrameworkTest {

private static String pluginDirectory;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This file is heavily refactored and changed to easily form the test cases for the authorization and to support a test cases for substacks. All important test functions in the previous version have been converted to the array of parameters in the new version.

} catch (Exception ex) {
Assert.fail("invokeRemoveAll should not throw an exception");
}
env.setPluginStack(new AuthorizationStack(AuthControlFlag.REQUIRED, "default-stack"));
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is necessary because the application changes the stack at runtime directly into env and does not have its local copy in the auth. framework.


private final String role;

private AuthControlFlag(String role) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

there is still a bit of schizophrenia in the naming - role vs. control flag.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

so all should be flag as in pam list?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

@tulinkry tulinkry force-pushed the auth-stacks branch 3 times, most recently from a3a5643 to e04b811 Compare April 24, 2017 16:14
import org.opensolaris.opengrok.configuration.Nameable;

/**
*
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should have some description of the purpose

}

/**
* Load all authorization checks in this stack.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

"checks" should probably be replaced with different term.

return SUFFICIENT.equals(this);
}

public static AuthControlFlag get(String flag) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

javadoc

try {
return AuthControlFlag.valueOf(flag.toUpperCase());
} catch (IllegalArgumentException ex) {
// role does not exist -> add some more info about which roles do exist
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

role

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

} catch (IllegalArgumentException ex) {
// role does not exist -> add some more info about which roles do exist
throw new IllegalArgumentException(
String.format("No authorization flag \"%s\", available flags are [%s]. %s",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

control flag

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed

* Test the given entity if it should be allowed with this authorization
* check.
*
* @param entity the given entity
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

project/group - the terminology clashes a bit here

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

added a more detailed comment

try {
/**
* The exception should not happen here as we already have an
* instance of IAuthoriazationPlugin. But is is required by the
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

typo

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed

* Load all authorization entities in this stack.
*
* <p>
* If the method is unable to load all the entities contained in this stack
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does not match the code below + explain the rationale (why this is done)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

changed both code and the comment + added the purpose

*
* @param s the entity to remove
*/
public void remove(AuthorizationEntity s) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

how does the unload/remove work in general w.r.t. incoming requests ? If the Configuration is being reloaded and the authorization stack deconstructed what mechanism is used to ensure that the evaluation of the request waits until the stack is fully loaded ?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added a synchronized block over the stack replacement and changed couple of stuff:

  • the stack is copied from the configuration (not just the reference)

The reload is made like:

  1. construct a new copy of the configuration stack
  2. load plugins into this new copy
  3. replace the old stack with the new stack in the synchronized block (this should be fast as it's just a reference swap)
  4. free the old stack

/**
* Set the plugin to all classes in this stack which requires this class in
* the configuration. This creates a new instance of the plugin for each
* class which needs it.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

explain why this is necessary

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

explained

@vladak
Copy link
Member

vladak commented Apr 26, 2017

Other than the partial comments I had this looks good, feel free to merge.

@tulinkry
Copy link
Contributor Author

Check the new addition, it should be fine by now

loadAllPlugins();
loadAllPlugins(newStack);

// replace the stack in a synchronized block
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

explain why synchonized is used

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

explained, waiting for the travis to finish

@vladak
Copy link
Member

vladak commented Apr 28, 2017

Ok, merge then.

@tulinkry tulinkry merged commit 0770c90 into oracle:master Apr 28, 2017
@tulinkry tulinkry deleted the auth-stacks branch April 28, 2017 09:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants