Home > Articles > Programming > Java

  • Print
  • + Share This
This chapter is from the book

User Authentication

The Java Authentication and Authorization Service (JAAS) is a part of Java SE 1.4 and beyond. The "authentication" part is concerned with ascertaining the identity of a program user. The "authorization" part maps users to permissions.

JAAS is a "pluggable" API that isolates Java applications from the particular technology used to implement authentication. It supports, among others, UNIX logins, NT logins, Kerberos authentication, and certificate-based authentication.

Once a user has been authenticated, you can attach a set of permissions. For example, here we grant Harry a particular set of permissions that other users do not have:

grant principal com.sun.security.auth.UnixPrincipal "harry"
{
   permission java.util.PropertyPermission "user.*", "read";
   . . .
};

The com.sun.security.auth.UnixPrincipal class checks the name of the UNIX user who is running this program. Its getName method returns the UNIX login name, and we check whether that name equals "harry".

You use a LoginContext to allow the security manager to check such a grant statement. Here is the basic outline of the login code:

try
{
   System.setSecurityManager(new SecurityManager());
   LoginContext context = new LoginContext("Login1"); // defined in JAAS configuration file
   context.login();
   // get the authenticated Subject
   Subject subject = context.getSubject();
   . . .
   context.logout();
}
catch (LoginException exception) // thrown if login was not successful
{
   exception.printStackTrace();
}

Now the subject denotes the individual who has been authenticated.

The string parameter "Login1" in the LoginContext constructor refers to an entry with the same name in the JAAS configuration file. Here is a sample configuration file:

Login1
{
   com.sun.security.auth.module.UnixLoginModule required;
   com.whizzbang.auth.module.RetinaScanModule sufficient;
};

Login2
{
   . . .
};

Of course, the JDK contains no biometric login modules. The following modules are supplied in the com.sun.security.auth.module package:

UnixLoginModule
NTLoginModule
Krb5LoginModule
JndiLoginModule
KeyStoreLoginModule

A login policy consists of a sequence of login modules, each of which is labeled required, sufficient, requisite, or optional. The meaning of these keywords is given by the following algorithm:

  1. The modules are executed in turn, until a sufficient module succeeds, a requisite module fails, or the end of the module list is reached.
  2. Authentication is successful if all required and requisite modules succeed, or if none of them were executed, if at least one sufficient or optional module succeeds.

A login authenticates a subject, which can have multiple principals. A principal describes some property of the subject, such as the user name, group ID, or role. As you saw in the grant statement, principals govern permissions. The com.sun.security.auth.UnixPrincipal describes the UNIX login name, and the UnixNumericGroupPrincipal can test for membership in a UNIX group.

A grant clause can test for a principal, with the syntax

grant principalClass "principalName"

For example:

grant com.sun.security.auth.UnixPrincipal "harry"

When a user has logged in, you then run, in a separate access control context, the code that requires checking of principals. Use the static doAs or doAsPrivileged method to start a new PrivilegedAction whose run method executes the code.

Both of those methods execute an action by calling the run method of an object that implements the PrivilegedAction interface, using the permissions of the subject's principals:

PrivilegedAction<T> action = new
   PrivilegedAction()
   {
      public T run()
      {
        // run with permissions of subject principals
         . . .
      }
   };
T result = Subject.doAs(subject, action); // or Subject.doAsPrivileged(subject, action, null)

If the actions can throw checked exceptions, then you implement the PrivilegedExceptionAction interface instead.

The difference between the doAs and doAsPrivileged methods is subtle. The doAs method starts out with the current access control context, whereas the doAsPrivileged method starts out with a new context. The latter method allows you to separate the permissions for the login code and the "business logic." In our example application, the login code has permissions

permission javax.security.auth.AuthPermission "createLoginContext.Login1";
permission javax.security.auth.AuthPermission "doAsPrivileged";

The authenticated user has a permission

permission java.util.PropertyPermission "user.*", "read";

If we had used doAs instead of doAsPrivileged, then the login code would have also needed that permission!

The program in Listing 9-6 and Listing 9-7 demonstrates how to restrict permissions to certain users. The AuthTest program authenticates a user and then runs a simple action that retrieves a system property.

To make this example work, package the code for the login and the action into two separate JAR files:

javac *.java
jar cvf login.jar AuthTest.class
jar cvf action.jar SysPropAction.class

If you look at the policy file in Listing 9-8, you will see that the UNIX user with the name harry has the permission to read all files. Change harry to your login name. Then run the command

java -classpath login.jar:action.jar
   -Djava.security.policy=AuthTest.policy
   -Djava.security.auth.login.config=jaas.config
   AuthTest

Listing 9-12 shows the login configuration.

On Windows, change Unix to NT in both AuthTest.policy and jaas.config, and use a semicolon to separate the JAR files:

java -classpath login.jar;action.jar . . .

The AuthTest program should now display the value of the user.home property. However, if you change the login name in the AuthTest.policy file, then a security exception should be thrown because you no longer have the required permission.

Listing 9-6. AuthTest.java

 
 1. import java.security.*;
 2. import javax.security.auth.*;
 3. import javax.security.auth.login.*;
 4.
 5. /**
 6.  * This program authenticates a user via a custom login and then executes the SysPropAction
 7.  * with the user's privileges.
 8.  * @version 1.01 2007-10-06
 9.  * @author Cay Horstmann
10.  */
11. public class AuthTest
12. {
13.    public static void main(final String[] args)
14.    {
15.       System.setSecurityManager(new SecurityManager());
16.       try
17.       {
18.          LoginContext context = new LoginContext("Login1");
19.          context.login();
20.          System.out.println("Authentication successful.");
21.          Subject subject = context.getSubject();
22.          System.out.println("subject=" + subject);
23.          PrivilegedAction<String> action = new SysPropAction("user.home");
24.          String result = Subject.doAsPrivileged(subject, action, null);
25.          System.out.println(result);
26.          context.logout();
27.       }
28.       catch (LoginException e)
29.       {
30.          e.printStackTrace();
31.       }
32.    }
33. }

Listing 9-7. SysPropAction.java

 
 1. import java.security.*;
 2.
 3. /**
 4.    This action looks up a system property.
 5.  * @version 1.01 2007-10-06
 6.  * @author Cay Horstmann
 7. */
 8. public class SysPropAction implements PrivilegedAction<String>
 9. {
10.    /**
11.       Constructs an action for looking up a given property.
12.       @param propertyName the property name (such as "user.home")
13.    */
14.    public SysPropAction(String propertyName) { this.propertyName = propertyName; }
15.
16.    public String run()
17.    {
18.       return System.getProperty(propertyName);
19.    }
20.
21.    private String propertyName;
22. }

Listing 9-8. AuthTest.policy

 
 1. grant codebase "file:login.jar"
 2. {
 3.    permission javax.security.auth.AuthPermission "createLoginContext.Login1";
 4.    permission javax.security.auth.AuthPermission "doAsPrivileged";
 5. };
 6.
 7. grant principal com.sun.security.auth.UnixPrincipal "harry"
 8. {
 9.    permission java.util.PropertyPermission "user.*", "read";
10. };
  • LoginContext(String name)

    constructs a login context. The name corresponds to the login descriptor in the JAAS configuration file.

  • void login()

    establishes a login or throws LoginException if the login failed. Invokes the login method on the managers in the JAAS configuration file.

  • void logout()

    logs out the subject. Invokes the logout method on the managers in the JAAS configuration file.

  • Subject getSubject()

    returns the authenticated subject.

  • Set<Principal> getPrincipals()

    gets the principals of this subject.

  • static Object doAs(Subject subject, PrivilegedAction action)
  • static Object doAs(Subject subject, PrivilegedExceptionAction action)
  • static Object doAsPrivileged(Subject subject, PrivilegedAction action, AccessControlContext context)
  • static Object doAsPrivileged(Subject subject, PrivilegedExceptionAction action, AccessControlContext context)

    executes the privileged action on behalf of the subject. Returns the return value of the run method. The doAsPrivileged methods execute the action in the given access control context. You can supply a "context snapshot" that you obtained earlier by calling the static method AccessController.getContext(), or you can supply null to execute the code in a new context.

  • Object run()

    You must define this method to execute the code that you want to have executed on behalf of a subject.

  • Object run()

    You must define this method to execute the code that you want to have executed on behalf of a subject. This method may throw any checked exceptions.

  • String getName()

    returns the identifying name of this principal.

JAAS Login Modules

In this section, we look at a JAAS example that shows you

  • How to implement your own login module.
  • How to implement role-based authentication.

Supplying your own login module is useful if you store login information in a database. Even if you are happy with the default module, studying a custom module will help you understand the JAAS configuration file options.

Role-based authentication is essential if you manage a large number of users. It would be impractical to put the names of all legitimate users into a policy file. Instead, the login module should map users to roles such as "admin" or "HR," and the permissions should be based on these roles.

One job of the login module is to populate the principal set of the subject that is being authenticated. If a login module supports roles, it adds Principal objects that describe roles. The Java library does not provide a class for this purpose, so we wrote our own (see Listing 9-9). The class simply stores a description/value pair, such as role=admin. Its getName method returns that pair, so we can add role-based permissions into a policy file:

grant principal SimplePrincipal "role=admin" { . . . }

Our login module looks up users, passwords, and roles in a text file that contains lines like this:

harry|secret|admin
carl|guessme|HR

Of course, in a realistic login module, you would store this information in a database or directory.

You can find the code for the SimpleLoginModule in Listing 9-10. The checkLogin method checks whether the user name and password match a user record in the password file. If so, we add two SimplePrincipal objects to the subject's principal set:

Set<Principal> principals = subject.getPrincipals();
principals.add(new SimplePrincipal("username", username));
principals.add(new SimplePrincipal("role", role));

The remainder of SimpleLoginModule is straightforward plumbing. The initialize method receives

  • The Subject that is being authenticated.
  • A handler to retrieve login information.
  • A sharedState map that can be used for communication between login modules.
  • An options map that contains name/value pairs that are set in the login configuration.

For example, we configure our module as follows:

SimpleLoginModule required pwfile="password.txt";

The login module retrieves the pwfile settings from the options map.

The login module does not gather the user name and password; that is the job of a separate handler. This separation allows you to use the same login module without worrying whether the login information comes from a GUI dialog box, a console prompt, or a configuration file.

The handler is specified when you construct the LoginContext, for example,

LoginContext context = new LoginContext("Login1",
   new com.sun.security.auth.callback.DialogCallbackHandler());

The DialogCallbackHandler pops up a simple GUI dialog box to retrieve the user name and password. com.sun.security.auth.callback.TextCallbackHandler gets the information from the console.

However, in our application, we have our own GUI for collecting the user name and password (see Figure 9-10). We produce a simple handler that merely stores and returns that information (see Listing 9-11).

Figure 9-10

Figure 9-10 A custom login module

The handler has a single method, handle, that processes an array of Callback objects. A number of predefined classes, such as NameCallback and PasswordCallback, implement the Callback interface. You could also add your own class, such as RetinaScanCallback. The handler code is a bit unsightly because it needs to analyze the types of the callback objects:

public void handle(Callback[] callbacks)
{
   for (Callback callback : callbacks)
   {
      if (callback instanceof NameCallback) . . .
      else if (callback instanceof PasswordCallback) . . .
      else . . .
   }
}

The login module prepares an array of the callbacks that it needs for authentication:

NameCallback nameCall = new NameCallback("username: ");
PasswordCallback passCall = new PasswordCallback("password: ", false);
callbackHandler.handle(new Callback[] { nameCall, passCall });

Then it retrieves the information from the callbacks.

The program in Listing 9-12 displays a form for entering the login information and the name of a system property. If the user is authenticated, the property value is retrieved in a PrivilegedAction. As you can see from the policy file in Listing 9-13, only users with the admin role have permission to read properties.

As in the preceding section, you must separate the login and action code. Create two JAR files:

javac *.java
jar cvf login.jar JAAS*.class Simple*.class
jar cvf action.jar SysPropAction.class

Then run the program as

java -classpath login.jar:action.jar
   -Djava.security.policy=JAASTest.policy
   -Djava.security.auth.login.config=jaas.config
   JAASTest

Listing 9-14 shows the login configuration.

Listing 9-9. SimplePrincipal.java

 
 1. import java.security.*;
 2.
 3. /**
 4.  * A principal with a named value (such as "role=HR" or "username=harry").
 5.  * @version 1.0 2004-09-14
 6.  * @author Cay Horstmann
 7.  */
 8. public class SimplePrincipal implements Principal
 9. {
10.    /**
11.     * Constructs a SimplePrincipal to hold a description and a value.
12.     * @param roleName the role name
13.     */
14.    public SimplePrincipal(String descr, String value)
15.    {
16.       this.descr = descr;
17.       this.value = value;
18.    }
19.
20.    /**
21.     * Returns the role name of this principal
22.     * @return the role name
23.     */
24.    public String getName()
25.    {
26.       return descr + "=" + value;
27.    }
28.
29.    public boolean equals(Object otherObject)
30.    {
31.       if (this == otherObject) return true;
32.       if (otherObject == null) return false;
33.       if (getClass() != otherObject.getClass()) return false;
34.       SimplePrincipal other = (SimplePrincipal) otherObject;
35.       return getName().equals(other.getName());
36.    }
37.
38.    public int hashCode()
39.    {
40.       return getName().hashCode();
41.    }
42.
43.    private String descr;
44.    private String value;
45. }

Listing 9-10. SimpleLoginModule.java

  
  1. import java.io.*;
  2. import java.security.*;
  3. import java.util.*;
  4. import javax.security.auth.*;
  5. import javax.security.auth.callback.*;
  6. import javax.security.auth.login.*;
  7. import javax.security.auth.spi.*;
  8.
  9. /**
 10.  * This login module authenticates users by reading usernames, passwords, and roles from a
 11.  * text file.
 12.  * @version 1.0 2004-09-14
 13.  * @author Cay Horstmann
 14.  */
 15. public class SimpleLoginModule implements LoginModule
 16. {
 17.    public void initialize(Subject subject, CallbackHandler callbackHandler,
 18.          Map<String, ?> sharedState, Map<String, ?> options)
 19.    {
 20.       this.subject = subject;
 21.       this.callbackHandler = callbackHandler;
 22.       this.options = options;
 23.    } 
 24.
 25.    public boolean login() throws LoginException
 26.    {
 27.       if (callbackHandler == null) throw new LoginException("no handler");
 28.
 29.       NameCallback nameCall = new NameCallback("username: ");
 30.       PasswordCallback passCall = new PasswordCallback("password: ", false);
 31.       try
 32.       {
 33.          callbackHandler.handle(new Callback[] { nameCall, passCall });
 34.       }
 35.       catch (UnsupportedCallbackException e)
 36.       {
 37.          LoginException e2 = new LoginException("Unsupported callback");
 38.          e2.initCause(e);
 39.          throw e2;
 40.       }
 41.       catch (IOException e)
 42.       {
 43.          LoginException e2 = new LoginException("I/O exception in callback");
 44.          e2.initCause(e);
 45.          throw e2;
 46.       }
 47.
 48.       return checkLogin(nameCall.getName(), passCall.getPassword());
 49.    }
 50.
 51.    /**
 52.     * Checks whether the authentication information is valid. If it is, the subject acquires
 53.     * principals for the user name and role.
 54.     * @param username the user name
 55.     * @param password a character array containing the password
 56.     * @return true if the authentication information is valid
 57.     */
 58.    private boolean checkLogin(String username, char[] password) throws LoginException
 59.    {
 60.       try
 61.       {
 62.          Scanner in = new Scanner(new FileReader("" + options.get("pwfile")));
 63.          while (in.hasNextLine())
 64.          {
 65.             String[] inputs = in.nextLine().split("\\|");
 66.            if (inputs[0].equals(username) && Arrays.equals(inputs[1].toCharArray(), password))
 67.             {
 68.                String role = inputs[2];
 69.                Set<Principal> principals = subject.getPrincipals();
 70.                principals.add(new SimplePrincipal("username", username));
 71.                principals.add(new SimplePrincipal("role", role));
 72.                return true;
 73.             }
 74.          }
 75.          in.close();
 76.          return false;
 77.       }
 78.       catch (IOException e)
 79.       {
 80.          LoginException e2 = new LoginException("Can't open password file");
 81.          e2.initCause(e);
 82.          throw e2;
 83.       }
 84.    }
 85.
 86.    public boolean logout()
 87.    {
 88.       return true;
 89.    }
 90.
 91.    public boolean abort()
 92.    {
 93.       return true;
 94.    }
 95.
 96.    public boolean commit()
 97.    {
 98.       return true;
 99.    }
100.
101.    private Subject subject;
102.    private CallbackHandler callbackHandler;
103.    private Map<String, ?> options;
104. }

Listing 9-11. SimpleCallbackHandler.java

 
 1. import javax.security.auth.callback.*;
 2.
 3. /**
 4.  * This simple callback handler presents the given user name and password.
 5.  * @version 1.0 2004-09-14
 6.  * @author Cay Horstmann
 7.  */
 8. public class SimpleCallbackHandler implements CallbackHandler
 9. {
10.    /**
11.     * Constructs the callback handler.
12.     * @param username the user name
13.     * @param password a character array containing the password
14.     */
15.    public SimpleCallbackHandler(String username, char[] password)
16.    {
17.       this.username = username;
18.       this.password = password;
19.    }
20.
21.    public void handle(Callback[] callbacks)
22.    {
23.       for (Callback callback : callbacks)
24.       {
25.          if (callback instanceof NameCallback)
26.          {
27.             ((NameCallback) callback).setName(username);
28.          }
29.          else if (callback instanceof PasswordCallback)
30.          {
31.            ((PasswordCallback) callback).setPassword(password);
32.          }
33.       }
34.    }
35.
36.    private String username;
37.    private char[] password;
38. }

Listing 9-12. JAASTest.java

 
 1. import java.awt.*;
 2. import java.awt.event.*;
 3. import javax.security.auth.*;
 4. import javax.security.auth.login.*;
 5. import javax.swing.*;
 6.
 7. /**
 8.  * This program authenticates a user via a custom login and then executes the SysPropAction
 9.  * with the user's privileges.
10.  * @version 1.0 2004-09-14
11.  * @author Cay Horstmann
12.  */
13. public class JAASTest
14. {
15.    public static void main(final String[] args)
16.    {
17.       System.setSecurityManager(new SecurityManager());
18.       EventQueue.invokeLater(new Runnable()
19.          {
20.             public void run()
21.             {
22.                JFrame frame = new JAASFrame();
23.                frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
24.                frame.setVisible(true);
25.             }
26.          });
27.    }
28. }
29.
30. /**
31.  * This frame has text fields for user name and password, a field for the name of the requested
32.  * system property, and a field to show the property value.
33.  */
34. class JAASFrame extends JFrame
35. {
36.    public JAASFrame()
37.    {
38.       setTitle("JAASTest");
39.
40.       username = new JTextField(20);
41.       password = new JPasswordField(20);
42.       propertyName = new JTextField(20);
43.       propertyValue = new JTextField(20);
44.       propertyValue.setEditable(false);
45.
46.       JPanel panel = new JPanel();
47.       panel.setLayout(new GridLayout(0, 2));
48.       panel.add(new JLabel("username:"));
49.       panel.add(username);
50.       panel.add(new JLabel("password:"));
51.       panel.add(password);
52.       panel.add(propertyName);
53.       panel.add(propertyValue);
54.       add(panel, BorderLayout.CENTER);
55.
56.       JButton getValueButton = new JButton("Get Value");
57.       getValueButton.addActionListener(new ActionListener()
58.          {
59.             public void actionPerformed(ActionEvent event)
60.             {
61.                getValue();
62.             }
63.          });
64.       JPanel buttonPanel = new JPanel();
65.       buttonPanel.add(getValueButton);
66.       add(buttonPanel, BorderLayout.SOUTH);
67.       pack();
68.    }
69.
70.    public void getValue()
71.    {
72.       try
73.       {
74.          LoginContext context = new LoginContext("Login1", new SimpleCallbackHandler(username
75.             .getText(), password.getPassword()));
76.          context.login();
77.          Subject subject = context.getSubject();
78.          propertyValue.setText(""
79.            + Subject.doAsPrivileged(subject, new SysPropAction(propertyName.getText()), null));
80.          context.logout();
81.       }
82.       catch (LoginException e)
83.       {
84.          JOptionPane.showMessageDialog(this, e);
85.       }
86.    }
87.
88.    private JTextField username;
89.    private JPasswordField password;
90.    private JTextField propertyName;
91.    private JTextField propertyValue;
92. }

Listing 9-13. JAASTest.policy

 
 1. grant codebase "file:login.jar"
 2. {
 3.    permission java.awt.AWTPermission "showWindowWithoutWarningBanner";
 4.    permission javax.security.auth.AuthPermission "createLoginContext.Login1";
 5.    permission javax.security.auth.AuthPermission "doAsPrivileged";
 6.    permission javax.security.auth.AuthPermission "modifyPrincipals";
 7.    permission java.io.FilePermission "password.txt", "read";
 8. };
 9.
10. grant principal SimplePrincipal "role=admin"
11. {
12.    permission java.util.PropertyPermission "*", "read";
13. };

Listing 9-14. jaas.config

1. Login1
2. {
3.    SimpleLoginModule required pwfile="password.txt";
4. };
  • void handle(Callback[] callbacks)

    handles the given callbacks, interacting with the user if desired, and stores the security information in the callback objects.

  • NameCallback(String prompt)
  • NameCallback(String prompt, String defaultName)

    constructs a NameCallback with the given prompt and default name.

  • void setName(String name)
  • String getName()

    sets or gets the name gathered by this callback.

  • String getPrompt()

    gets the prompt to use when querying this name.

  • String getDefaultName()

    gets the default name to use when querying this name.

  • PasswordCallback(String prompt, boolean echoOn)

    constructs a PasswordCallback with the given prompt and echo flag.

  • void setPassword(char[] password)
  • char[] getPassword()

    sets or gets the password gathered by this callback.

  • String getPrompt()

    gets the prompt to use when querying this password.

  • boolean isEchoOn()

    gets the echo flag to use when querying this password.

  • void initialize(Subject subject, CallbackHandler handler, Map<String,?> sharedState, Map<String,?> options)

    initializes this LoginModule for authenticating the given subject. During login processing, uses the given handler to gather login information. Use the sharedState map for communication with other login modules. The options map contains the name/value pairs specified in the login configuration for this module instance.

  • boolean login()

    carries out the authentication process and populates the subject's principals. Returns true if the login was successful.

  • boolean commit()

    is called after all login modules were successful, for login scenarios that require a two-phase commit. Returns true if the operation was successful.

  • boolean abort()

    is called if the failure of another login module caused the login process to abort. Returns true if the operation was successful.

  • boolean logout()

    logs out this subject. Returns true if the operation was successful.

  • + Share This
  • 🔖 Save To Your Account

InformIT Promotional Mailings & Special Offers

I would like to receive exclusive offers and hear about products from InformIT and its family of brands. I can unsubscribe at any time.

Overview


Pearson Education, Inc., 221 River Street, Hoboken, New Jersey 07030, (Pearson) presents this site to provide information about products and services that can be purchased through this site.

This privacy notice provides an overview of our commitment to privacy and describes how we collect, protect, use and share personal information collected through this site. Please note that other Pearson websites and online products and services have their own separate privacy policies.

Collection and Use of Information


To conduct business and deliver products and services, Pearson collects and uses personal information in several ways in connection with this site, including:

Questions and Inquiries

For inquiries and questions, we collect the inquiry or question, together with name, contact details (email address, phone number and mailing address) and any other additional information voluntarily submitted to us through a Contact Us form or an email. We use this information to address the inquiry and respond to the question.

Online Store

For orders and purchases placed through our online store on this site, we collect order details, name, institution name and address (if applicable), email address, phone number, shipping and billing addresses, credit/debit card information, shipping options and any instructions. We use this information to complete transactions, fulfill orders, communicate with individuals placing orders or visiting the online store, and for related purposes.

Surveys

Pearson may offer opportunities to provide feedback or participate in surveys, including surveys evaluating Pearson products, services or sites. Participation is voluntary. Pearson collects information requested in the survey questions and uses the information to evaluate, support, maintain and improve products, services or sites, develop new products and services, conduct educational research and for other purposes specified in the survey.

Contests and Drawings

Occasionally, we may sponsor a contest or drawing. Participation is optional. Pearson collects name, contact information and other information specified on the entry form for the contest or drawing to conduct the contest or drawing. Pearson may collect additional personal information from the winners of a contest or drawing in order to award the prize and for tax reporting purposes, as required by law.

Newsletters

If you have elected to receive email newsletters or promotional mailings and special offers but want to unsubscribe, simply email information@informit.com.

Service Announcements

On rare occasions it is necessary to send out a strictly service related announcement. For instance, if our service is temporarily suspended for maintenance we might send users an email. Generally, users may not opt-out of these communications, though they can deactivate their account information. However, these communications are not promotional in nature.

Customer Service

We communicate with users on a regular basis to provide requested services and in regard to issues relating to their account we reply via email or phone in accordance with the users' wishes when a user submits their information through our Contact Us form.

Other Collection and Use of Information


Application and System Logs

Pearson automatically collects log data to help ensure the delivery, availability and security of this site. Log data may include technical information about how a user or visitor connected to this site, such as browser type, type of computer/device, operating system, internet service provider and IP address. We use this information for support purposes and to monitor the health of the site, identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents and appropriately scale computing resources.

Web Analytics

Pearson may use third party web trend analytical services, including Google Analytics, to collect visitor information, such as IP addresses, browser types, referring pages, pages visited and time spent on a particular site. While these analytical services collect and report information on an anonymous basis, they may use cookies to gather web trend information. The information gathered may enable Pearson (but not the third party web trend services) to link information with application and system log data. Pearson uses this information for system administration and to identify problems, improve service, detect unauthorized access and fraudulent activity, prevent and respond to security incidents, appropriately scale computing resources and otherwise support and deliver this site and its services.

Cookies and Related Technologies

This site uses cookies and similar technologies to personalize content, measure traffic patterns, control security, track use and access of information on this site, and provide interest-based messages and advertising. Users can manage and block the use of cookies through their browser. Disabling or blocking certain cookies may limit the functionality of this site.

Do Not Track

This site currently does not respond to Do Not Track signals.

Security


Pearson uses appropriate physical, administrative and technical security measures to protect personal information from unauthorized access, use and disclosure.

Children


This site is not directed to children under the age of 13.

Marketing


Pearson may send or direct marketing communications to users, provided that

  • Pearson will not use personal information collected or processed as a K-12 school service provider for the purpose of directed or targeted advertising.
  • Such marketing is consistent with applicable law and Pearson's legal obligations.
  • Pearson will not knowingly direct or send marketing communications to an individual who has expressed a preference not to receive marketing.
  • Where required by applicable law, express or implied consent to marketing exists and has not been withdrawn.

Pearson may provide personal information to a third party service provider on a restricted basis to provide marketing solely on behalf of Pearson or an affiliate or customer for whom Pearson is a service provider. Marketing preferences may be changed at any time.

Correcting/Updating Personal Information


If a user's personally identifiable information changes (such as your postal address or email address), we provide a way to correct or update that user's personal data provided to us. This can be done on the Account page. If a user no longer desires our service and desires to delete his or her account, please contact us at customer-service@informit.com and we will process the deletion of a user's account.

Choice/Opt-out


Users can always make an informed choice as to whether they should proceed with certain services offered by InformIT. If you choose to remove yourself from our mailing list(s) simply visit the following page and uncheck any communication you no longer want to receive: www.informit.com/u.aspx.

Sale of Personal Information


Pearson does not rent or sell personal information in exchange for any payment of money.

While Pearson does not sell personal information, as defined in Nevada law, Nevada residents may email a request for no sale of their personal information to NevadaDesignatedRequest@pearson.com.

Supplemental Privacy Statement for California Residents


California residents should read our Supplemental privacy statement for California residents in conjunction with this Privacy Notice. The Supplemental privacy statement for California residents explains Pearson's commitment to comply with California law and applies to personal information of California residents collected in connection with this site and the Services.

Sharing and Disclosure


Pearson may disclose personal information, as follows:

  • As required by law.
  • With the consent of the individual (or their parent, if the individual is a minor)
  • In response to a subpoena, court order or legal process, to the extent permitted or required by law
  • To protect the security and safety of individuals, data, assets and systems, consistent with applicable law
  • In connection the sale, joint venture or other transfer of some or all of its company or assets, subject to the provisions of this Privacy Notice
  • To investigate or address actual or suspected fraud or other illegal activities
  • To exercise its legal rights, including enforcement of the Terms of Use for this site or another contract
  • To affiliated Pearson companies and other companies and organizations who perform work for Pearson and are obligated to protect the privacy of personal information consistent with this Privacy Notice
  • To a school, organization, company or government agency, where Pearson collects or processes the personal information in a school setting or on behalf of such organization, company or government agency.

Links


This web site contains links to other sites. Please be aware that we are not responsible for the privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of each and every web site that collects Personal Information. This privacy statement applies solely to information collected by this web site.

Requests and Contact


Please contact us about this Privacy Notice or if you have any requests or questions relating to the privacy of your personal information.

Changes to this Privacy Notice


We may revise this Privacy Notice through an updated posting. We will identify the effective date of the revision in the posting. Often, updates are made to provide greater clarity or to comply with changes in regulatory requirements. If the updates involve material changes to the collection, protection, use or disclosure of Personal Information, Pearson will provide notice of the change through a conspicuous notice on this site or other appropriate way. Continued use of the site after the effective date of a posted revision evidences acceptance. Please contact us if you have questions or concerns about the Privacy Notice or any objection to any revisions.

Last Update: November 17, 2020