GeezerVison is showing javaee.github.io — Using Programmatic Security with Web Applications
Java Platform, Enterprise Edition (Java EE) 8
The Java EE Tutorial
|
Using Programmatic Security with Web Applications
Programmatic security is used by security-aware applications when
declarative security alone is not sufficient to express the security
model of the application.
The following topics are addressed here:
Authenticating Users Programmatically
You can use the SecurityContext and HttpServletRequest interfaces to
authenticate users for a web application programmatically.
SecurityContext
The SecurityContext interface, as specified in the Java EE Security API
specification, defines the following method to programmatically trigger the
authentication process:
Programmatically triggering means that the container responds as if the caller
had attempted to access a constrained resource. It causes the container to invoke
the authentication mechanism configured for the application. If the configured
authentication mechanism is an HttpAuthenticationMechanism, then
the AuthenticationParameters argument is meaningful and extended capabilities of
HttpAuthenticationMechanism are available. If not, the behavior and result is
as if HttpServletRequest.authenticate() were called.
HttpServletRequest
The HttpServletRequest interface defines the following methods that enable you
to authenticate users for a web application programmatically.
-
authenticate allows an application to instigate authentication of
the request caller by the container from within an unconstrained request
context. A login dialog box displays and collects the user name and
password for authentication purposes.
-
login allows an application to collect user name and password
information as an alternative to specifying form-based authentication in
an application deployment descriptor.
-
logout allows an application to reset the caller identity of a
request.
The following example code shows how to use the login and logout
methods:
package test;
import java.io.IOException;
import java.io.PrintWriter;
import java.math.BigDecimal;
import javax.ejb.EJB;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@WebServlet(name="TutorialServlet", urlPatterns={"/TutorialServlet"})
public class TutorialServlet extends HttpServlet {
@EJB
private ConverterBean converterBean;
/**
* Processes requests for both HTTP <code>GET</code>
* and <code>POST</code> methods.
* @param request servlet request
* @param response servlet response
* @throws ServletException if a servlet-specific error occurs
* @throws IOException if an I/O error occurs
*/
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
out.println("<html>");
out.println("<head>");
out.println("<title>Servlet TutorialServlet</title>");
out.println("</head>");
out.println("<body>");
request.login("TutorialUser", "TutorialUser");
BigDecimal result =
converterBean.dollarToYen(new BigDecimal("1.0"));
out.println("<h1>Servlet TutorialServlet result of dollarToYen= "
+ result + "</h1>");
out.println("</body>");
out.println("</html>");
} catch (Exception e) {
throw new ServletException(e);
} finally {
request.logout();
out.close();
}
}
}
The following example code shows how to use the authenticate method:
package com.example.test;
import java.io.*;
import javax.servlet.*;
import javax.servlet.http.*;
public class TestServlet extends HttpServlet {
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
request.authenticate(response);
out.println("Authenticate Successful");
} finally {
out.close();
}
}
Checking Caller Identity Programmatically
In general, the container enforces security management in a
manner that is transparent to the web component. Use the security APIs
described in this section only in the less frequent
situations in which the web component methods need to access the
security context information.
The Java EE Security API specification defines the following methods of the
SecurityContext interface that allow the application to test aspects of the
caller data:
-
getCallerPrincipal() retrieves the Principal representing the caller.
This is the container-specific representation of the caller principal,
and the type may differ from the type of the caller principal originally
established by an HttpAuthenticationMechanism. This method returns null for an
unauthenticated caller.
-
getPrincipalsByType() retrieves all principals of the given type. This
method can be used to retrieve an application-specific caller principal
established during authentication. This method is primarily useful in the case
that the container’s caller principal is a different type than the application
caller principal, and the application needs specific information behavior
available only from the application principal. This method returns an empty
Set if the caller is unauthenticated, or if the requested type is not found.
Where both a container caller principal and an application caller principal
are present, the value returned by getName() is the same for both
principals.
-
isCallerInRole() takes a String argument that represents the role to be
tested. The specification does not define how the role determination is made,
but the result must be the same as if the corresponding container-specific call
had been made (for example HttpServletRequest.isUserInRole(),
EJBContext.isCallerInRole()), and must be consistent with the result implied
by specifications that prescribe role-mapping behavior.
Servlet 4.0 specifies the following methods that enable you to access
security information about the component’s caller.
-
getRemoteUser determines the user name with which the client
authenticated. The getRemoteUser method returns the name of the remote
user (the caller) associated by the container with the request. If no
user has been authenticated, this method returns null.
-
isUserInRole determines whether a remote user is in a specific
security role. If no user has been authenticated, this method returns
false. This method expects a String user role-name parameter.
The security-role-ref element should be declared in the deployment
descriptor with a role-name subelement containing the role name to be
passed to the method. Using security role references is discussed in
Declaring and Linking Role References.
-
getUserPrincipal determines the principal name of the current user
and returns a java.security.Principal object. If no user has been
authenticated, this method returns null. Calling the getName method
on the Principal returned by getUserPrincipal returns the name of
the remote user.
Your application can make business-logic decisions based on the
information obtained using these APIs.
Testing Access to a Resource Programmatically
The SecurityContext interface, as specified in the Java EE Security API
specification, defines the following method for programmatically testing
access to a resource:
For example, consider the following Servlet definition:
@WebServlet("/protectedServlet")
@ServletSecurity(@HttpConstraint(rolesAllowed = "foo"))
public class ProtectedServlet extends HttpServlet { ... }
And the following call to hasAccessToWebResource():
securityContext.hasAccessToWebResource("/protectedServlet", GET)
The above hasAccessToWebResource() call returns true if, and only if,
the caller is in role "foo".
Example Code for Programmatic Security
The following code demonstrates the use of programmatic security for the
purposes of programmatic login. This servlet does the following.
-
It displays information about the current user.
-
It prompts the user to log in.
-
It prints out the information again to demonstrate the effect of the
login method.
-
It logs the user out.
-
It prints out the information again to demonstrate the effect of the
logout method.
package enterprise.programmatic_login;
import java.io.*;
import java.net.*;
import javax.annotation.security.DeclareRoles;
import javax.servlet.*;
import javax.servlet.http.*;
@DeclareRoles("javaeeuser")
public class LoginServlet extends HttpServlet {
/**
* Processes requests for both HTTP GET and POST methods.
* @param request servlet request
* @param response servlet response
*/
protected void processRequest(HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
response.setContentType("text/html;charset=UTF-8");
PrintWriter out = response.getWriter();
try {
String userName = request.getParameter("txtUserName");
String password = request.getParameter("txtPassword");
out.println("Before Login" + "<br><br>");
out.println("IsUserInRole?.."
+ request.isUserInRole("javaeeuser")+"<br>");
out.println("getRemoteUser?.." + request.getRemoteUser()+"<br>");
out.println("getUserPrincipal?.."
+ request.getUserPrincipal()+"<br>");
out.println("getAuthType?.." + request.getAuthType()+"<br><br>");
try {
request.login(userName, password);
} catch(ServletException ex) {
out.println("Login Failed with a ServletException.."
+ ex.getMessage());
return;
}
out.println("After Login..."+"<br><br>");
out.println("IsUserInRole?.."
+ request.isUserInRole("javaeeuser")+"<br>");
out.println("getRemoteUser?.." + request.getRemoteUser()+"<br>");
out.println("getUserPrincipal?.."
+ request.getUserPrincipal()+"<br>");
out.println("getAuthType?.." + request.getAuthType()+"<br><br>");
request.logout();
out.println("After Logout..."+"<br><br>");
out.println("IsUserInRole?.."
+ request.isUserInRole("javaeeuser")+"<br>");
out.println("getRemoteUser?.." + request.getRemoteUser()+"<br>");
out.println("getUserPrincipal?.."
+ request.getUserPrincipal()+"<br>");
out.println("getAuthType?.." + request.getAuthType()+"<br>");
} finally {
out.close();
}
}
...
}
Declaring and Linking Role References
A security role reference is a mapping between the name of a role that
is called from a web component using isUserInRole(String role) and the
name of a security role that has been defined for the application. If no
security-role-ref element is declared in a deployment descriptor and
the isUserInRole method is called, the container defaults to checking
the provided role name against the list of all security roles defined
for the web application. Using the default method instead of using the
security-role-ref element limits your flexibility to change role names
in an application without also recompiling the servlet making the call.
The security-role-ref element is used when an application uses the
HttpServletRequest.isUserInRole(String role). The value passed to the
isUserInRole method is a String representing the role name of the
user. The value of the role-name element must be the String used as
the parameter to the HttpServletRequest.isUserInRole(String role). The
role-link must contain the name of one of the security roles defined
in the security-role elements. The container uses the mapping of
security-role-ref to security-role when determining the return value
of the call.
For example, to map the security role reference cust to the security
role with role name bankCustomer, the elements would look like this:
<servlet>
...
<security-role-ref>
<role-name>cust</role-name>
<role-link>bankCustomer</role-link>
</security-role-ref>
...
</servlet>
If the servlet method is called by a user in the bankCustomer security
role, isUserInRole("cust") returns true.
The role-link element in the security-role-ref element must match a
role-name defined in the security-role element of the same web.xml
deployment descriptor, as shown here:
<security-role>
<role-name>bankCustomer</role-name>
</security-role>
A security role reference, including the name defined by the reference,
is scoped to the component whose deployment descriptor contains the
security-role-ref deployment descriptor element.
Copyright © 2017, Oracle and/or its affiliates. All rights reserved.
|