The Java platform provides authentication and authorization services (Java Authentication and Authorization service (JAAS)) that can control code access to sensitive or critical resources, such as file systems, network services, System attribute access, etc. Enhance the security of your code. Mainly includes authentication and authorization two parts, the purpose of authentication is to reliably determine who is currently executing code, code can be an application, applet,bean,servlet; The purpose of authorization is to determine what permissions the user currently executing the code has, and whether the resource can be accessed. Although Jaas is divided into two parts on the surface, in fact, both are inseparable, here is a snippet of code:
public class App {public static void main (string[] args) {System.out.println (System.getproperty ("Java.home"));}}
very simple just output java.home system properties, now there is no problem, the properties will be able to output normally. Replace the above code with the following:
public class App {public static void main (string[] args) {//install Security Manager system.setsecuritymanager (New SecurityManager ()); System.out.println (System.getproperty ("Java.home"));}}
The following exception was thrown: Java.security.AccessControlException:access denied ("Java.util.PropertyPermission" "Java.home" "read") , the exception prompt does not have the Read permission to the Java.home, the system attribute is also a kind of resource, similar to file access; By default, no security Manager is installed for a normal Java application, and after manually installing the Security Manager, if no permissions are granted for the app, the app cannot access the Java.home system Properties 。
Authorization is a way to bind an authorization policy file to the security manager. Since I was running the main method directly in the Eclipse Java project, I created a new Demo.policy file in the project root directory with the following contents:
Grant {Permission Java.util.PropertyPermission "Java.home", "read";};
The effect of this authorization is that any user running any program has read access to Java.home, the specific format of the policy file can be see: http://docs.oracle.com/javase/7/docs/technotes/guides/ Security/policyfiles.html
There are two ways to bind the policy file to the security Manager: First, add the-djava.security.policy=demo.policy virtual machine startup parameters while running the program, and execute System.setproperty (" Java.security.policy "," Demo.policy "); in fact, the effect of the two is to set the system properties, where Demo.policy is the path, here in order to simply specify a relative path, the absolute path is certainly not a problem. Running the program again no longer throws an exception, stating that the program has read access to the Java.home system properties. There are many permissions in Java, which can be consulted: http://docs.oracle.com/javase/7/docs/technotes/guides/security/spec/security-spec.doc3.html#17001
In the above process although the authorization is completed, but the authorization of the target is not strong, after the program binding the policy file, regardless of which user execution will have the Java.home System Properties Read permission, now we want to do more granular permission control, here need to use the authentication service.
Certification services A little "trouble", the general situation is mainly involved in the Logincontext,loginmodule,callbackhandler,principal, the latter three also need to implement their own developers. Here are some explanations of the functions of these classes:
1.LoginContext: The authentication core class, also is the entry class, is used to trigger the login authentication, the specific login module is specified by the constructor method name parameter
2.LoginModule: Login module, encapsulating the specific login authentication logic, if authentication fails, throws an exception, becomes add a principal to subject
3.CallbackHandler: Callback processor for collecting authentication information
4.Principal: Represents a program user's identity, which is closely related to subject, which is used to represent program users, and a user can multiple identities, authorization can be authorized for a user's multiple identities
Here is an example of authentication:
Package Com.xtayfjpk.security.jaas.demo;import Javax.security.auth.login.logincontext;import Javax.security.auth.login.loginexception;public class App {public static void main (string[] args) {System.setproperty ( "Java.security.auth.login.config", "demo.config"); System.setproperty ("Java.security.policy", "Demo.policy"); System.setsecuritymanager (New SecurityManager ()); try {//Create login context LoginContext context = new LoginContext ("Demo", New Democallbackhander ());//login, login unsuccessful the system exits Context.login (); catch (Loginexception le) { System.err.println ("Cannot create logincontext." + le.getmessage ()); System.exit (-1);} catch (SecurityException se) { System.err.println ("Cannot create logincontext." + se.getmessage ()); System.exit (-1);} Access Resource System.out.println (System.getproperty ("Java.home"));}}
Package Com.xtayfjpk.security.jaas.demo;import Java.io.ioexception;import Java.security.principal;import Java.util.iterator;import Java.util.map;import Javax.security.auth.subject;import Javax.security.auth.callback.callback;import Javax.security.auth.callback.callbackhandler;import Javax.security.auth.callback.namecallback;import Javax.security.auth.callback.passwordcallback;import Javax.security.auth.callback.unsupportedcallbackexception;import javax.security.auth.login.FailedLoginException ; Import Javax.security.auth.login.loginexception;import Javax.security.auth.spi.loginmodule;public class Demologinmodule implements Loginmodule {private Subject subject;private CallbackHandler callbackhandler;private Boolean success = false;private string user;private string password; @Overridepublic void Initialize (Subject Subject, call Backhandler CallbackHandler, map<string,?> sharedstate, map<string,?> options) {this.subject = subject; This.callbackhandler = CallbackHandler;} @OverridEpublic Boolean login () throws Loginexception {NameCallback namecallback = new NameCallback ("Please enter user name"); PasswordCallback passwordcallback = new PasswordCallback ("Please enter password", false); Callback[] callbacks = new Callback[]{namecallback, Passwordcallback};try {//execute callback, The callback process obtains the user name and password callbackhandler.handle (callbacks);//get username and password user = Namecallback.getname ();p assword = new String ( Passwordcallback.getpassword ());} catch (IOException | Unsupportedcallbackexception e) {success = False;throw new Failedloginexception ("User name or password acquisition failed");} For the sake of simplicity, the authentication condition writes dead if (User.length () >3 && password.length () >3) {success = true;//authentication succeeded}return true;} @Overridepublic Boolean commit () throws Loginexception {if (!success) {return false;} else {// If the authentication is successful, a principal object must be added to the subject//so that an identity user is authenticated and logged in to the application, indicating who is executing the program this.subject.getPrincipals (). Add (New Demoprincipal (user)); return true;}} @Overridepublic Boolean abort () throws Loginexception {logout (); return true;} @Overridepublic Boolean logout () throws Loginexception {//exits with the corresponding PrincipThe Al object is removed from the subject iterator<principal> iter = Subject.getprincipals (). iterator (); while (Iter.hasnext ()) { Principal Principal = Iter.next (); if (Principal instanceof Demoprincipal) {if (Principal.getname (). Equals (user)) { Iter.remove (); break;}}} return true;}}
Package Com.xtayfjpk.security.jaas.demo;import Java.io.ioexception;import Javax.security.auth.callback.Callback; Import Javax.security.auth.callback.callbackhandler;import Javax.security.auth.callback.namecallback;import Javax.security.auth.callback.passwordcallback;import javax.security.auth.callback.UnsupportedCallbackException; public class Democallbackhander implements CallbackHandler {@Overridepublic void handle (callback[] callbacks) throws IOException, unsupportedcallbackexception {namecallback namecallback = (namecallback) callbacks[0]; PasswordCallback PasswordCallback = (passwordcallback) callbacks[1];//set user name and password namecallback.setname ( Getuserfromsomewhere ());p Asswordcallback.setpassword (Getpasswordfromsomewhere (). ToCharArray ());} For the sake of simplicity, the username and password are returned directly, and the real situation can be obtained by user input such as public String Getuserfromsomewhere () {return "Zhangsan";} Public String Getpasswordfromsomewhere () {return ' Zhangsan ';}}
Package Com.xtayfjpk.security.jaas.demo;import Java.security.principal;public class Demoprincipal implements Principal {private string name;public Demoprincipal (String name) {this.name = name;} @Overridepublic String GetName () {return this.name;}}
When using the authentication service, you need to bind an authentication profile, in the example through System.setproperty ("Java.security.auth.login.config", "demo.config"); Of course, you can also set the virtual property-djava.security.auth.login.config=demo.config implementation. The contents of the configuration file are as follows:
Demo { com.xtayfjpk.security.jaas.demo.DemoLoginModule required debug=true;};
Where the demo is the configuration name, its content specifies which login module (loginmodule) to use, and the specific format of the authentication profile, see: http://docs.oracle.com/javase/6/docs/technotes/guides/ Security/jgss/tutorials/loginconfigfile.html
As mentioned above, certification and authorization are inseparable, here can be explained, When creating a LoginContext object, you need to have Createlogincontext.demo authentication permissions, and the demo is the configuration name in the authentication configuration file, which is specified when the LoginContext object is constructed. Because the principals collection of subject is modified in Demologinmodule, modifyprincipals authentication permission is also required, so the contents of the authorization policy file become:
Grant {Permission Javax.security.auth.AuthPermission "Createlogincontext.demo";p ermission Javax.security.auth.AuthPermission "Modifyprincipals";p ermission java.util.PropertyPermission "Java.home", "read";};
Run the program again, java.home the system Properties normal output, but at this time we still do not authorize a specific user identity, this need to configure principal in the authorization file, now the authorization file is rewritten as:
Grant Principal Com.xtayfjpk.security.jaas.demo.DemoPrincipal "Zhangsan" {Permission Java.util.PropertyPermission " Java.home "," read ";}; Grant {Permission Javax.security.auth.AuthPermission "Createlogincontext.demo";p ermission Javax.security.auth.AuthPermission "Modifyprincipals";p ermission javax.security.auth.AuthPermission " Doasprivileged ";};
This means that only the Demoprincipal login app named Zhangsan will have read access to the Java.home system Properties, and the code that reads Java.home needs to be modified as follows:
Subject Subject = Context.getsubject ();//The method call requires the "doasprivileged" Permission subject.doasprivileged (Subject, new Privilegedaction<object> () {@Overridepublic Object run () {System.out.println (System.getproperty ("Java.home") ); return null;}}, NULL);
because principal information is available in subject, a set of permissions schemes can be developed for each user identity.
Authentication and authorization of Java security