0

I have an AngularJS program that consumes RESTful services provided via GlassFish 4.1. I have authentication requirements for the RESTful services that are defined in the web.xml file. During development I have been relying on GlassFish to fire off a browser authentication request whenever the website tries to access a RESTful service, and this has worked just fine. Now, however, I am wanting to use ui-router and a login controller to send the username and password to GlassFish via an HTTP post. The HTTP post isn't working, so in the meantime I've just turned off the authentication requirement on the GlassFish side and have a mock login that pretends to perform a successful login to GlassFish, and then ui-router takes care of the rest after the user is "logged in". The routing after authentication is working beautifully, so no problems there. My issue comes down to this: how do I properly send username and password to the GlassFish server in its current configuration where authentication is required when accessing a service? Below is web.xml and the login controller. Thanks for any help.

web.xml

<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.1" xmlns="http://xmlns.jcp.org/xml/ns/javaee"  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/javaee http://xmlns.jcp.org/xml/ns/javaee/web-app_3_1.xsd">
   <session-config>
      <session-timeout>
         30
      </session-timeout>
   </session-config>
   <security-constraint>
        <web-resource-collection>
        <web-resource-name>Enforce TLS</web-resource-name>
        <description/>
        <url-pattern>/*</url-pattern>
        </web-resource-collection>
        <user-data-constraint>
           <!-- require SSL -->
            <description/>
            <transport-guarantee>CONFIDENTIAL</transport-guarantee>
        </user-data-constraint>
    </security-constraint>
    <security-constraint>
        <web-resource-collection>
            <web-resource-name>Secure Pages</web-resource-name>
            <description/>
            <url-pattern>/tsn/*</url-pattern>
        </web-resource-collection>
        <auth-constraint>
            <role-name>tsnadmin</role-name>
            <role-name>tester</role-name>
        </auth-constraint>
    <user-data-constraint>
        <description/>
        <transport-guarantee>CONFIDENTIAL</transport-guarantee>
    </user-data-constraint>
    </security-constraint>
   <login-config>
      <auth-method>BASIC</auth-method>
      <realm-name>tsnRealm</realm-name>
   </login-config>
   <security-role>
      <role-name>tsnadmin</role-name>
   </security-role>
   <security-role>
      <role-name>tester</role-name>
   </security-role>
</web-app>

The Controller:

'use strict';

angular.module('pisuiteClientExpApp')
    .controller('LoginModalCtrl', function (
            $scope,
            $timeout,
            $http,
            userRoles,
            auagByUserSvc) {
       this.cancel = $scope.$dismiss;

       /*this.submit = function () {
          $scope.dataLoading = true;
          $timeout(function () {
           $scope.user;
           if ($scope.username === 'rpurvis') {
           $scope.user = {uname: 'rpurvis', role: userRoles.tester,
           success: $scope.username === 'rpurvis' && $scope.password === 'password'};
           } else if ($scope.username === userRoles.admin) {
           $scope.user = {uname: userRoles.admin, role: userRoles.admin,
           success: $scope.username === userRoles.admin && $scope.password === 'password'};
           }
           if (!$scope.user.success) {
           $scope.user.message = 'Username or password is incorrect';
           $scope.user = null;
           $scope.$close($scope.user);
           } else {
           auagByUserSvc.get({user: $scope.user.uname}, function (auag_success) {
           /*console.log("setting images to an array of length: " + data.length)
           if (auag_success.length > 0) {
           $scope.user.role = auag_success[0].idAuthGroup.idAuthGroup;
           $scope.user.inspectorid = auag_success[0].idAuthUser.inspectorid;
           }
           $scope.$close($scope.user);
           }, function (error) {
           $scope.$close($scope.user);
           });
           }
           }, 1000);*/

          var req = {
             method: 'POST',
             url: 'https://localhost:9191/PISuiteService_Exp/',
             headers: {'Content-Type': 'application/x-www-form-urlencoded'},
             transformRequest: function (obj) {
                var str = [];
                for (var p in obj)
                   str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
                return str.join("&");
             },
             data: {username: $scope.username, password: $scope.password}
          };

          $http(req).then(function (success) {
             $scope.user = {uname: $scope.username};
             console.log("in post success");
             auagByUserSvc.get({user: $scope.username}, function (auag_success) {
                if (auag_success.length > 0) {
                   $scope.user.role = auag_success[0].idAuthGroup.idAuthGroup;
                   $scope.user.inspectorid = auag_success[0].idAuthUser.inspectorid;
                }
                $scope.$close($scope.user);
             }, function (error) {
                $scope.$close($scope.user);
             });
          }, function (error) {
             console.log("in post error");
             $scope.user.message = 'Username or password is incorrect';
             $scope.user = null;
             $scope.$close($scope.user);
          }, function (progress) {
             console.log("in post progress");
          });
       };
    });
OndroMih
  • 6,329
  • 1
  • 21
  • 38
R. Purvis
  • 1
  • 2

1 Answers1

0

In order to authenticate with REST server, you need to send Authorization token in header of each request. The value of the token starts with BASIC

"Authorization" = "Basic " + btoa(username + ":" + password)

Here is an example using jQuery: How to use Basic Auth with jQuery and AJAX?.

With angular, you would create your request like this (check out headers field):

    var req = {
         method: 'POST',
         url: 'https://localhost:9191/PISuiteService_Exp/',
         headers: {
           'Content-Type': 'application/x-www-form-urlencoded',
           'Authorization': 'Basic ' + btoa($scope.username + ':' + $scope.password),
         },
         transformRequest: function (obj) {
            var str = [];
            for (var p in obj)
               str.push(encodeURIComponent(p) + "=" + encodeURIComponent(obj[p]));
            return str.join("&");
         }
      };

The above stateless authentication with a REST service is recommended, as REST services should be stateless by definition.

However, you might want to authenticate in the beginning of a session once. This is probably what you had in place originally, as GlassFish triggered login form automatically when not authenticated, and kept login information for the rest of the session.

In that case, you may use form-based authentication in order to send login data by a POST request. For more details, look at Java EE tutorial, I will just post the form example from there:

<form method="POST" action="j_security_check">
<input type="text" name="j_username">
<input type="password" name="j_password">
</form>
Community
  • 1
  • 1
OndroMih
  • 6,329
  • 1
  • 21
  • 38
  • Thank you, OndrejM, for your response. Unfortunately, it still doesn't work. You mention that in order to authenticate to REST server, I need to send Authorization token with each header. However, this hasn't been the case when I relied solely on the GlassFish server to kick off an authentication request when it sends an HTTP 401 response to the first request for a REST service. I use angular factory service to access RESTful services, and didn't do anything particular in the HTTP requests to get the data. I authenticate once to the service, and that's it. I hope to keep it that way. – R. Purvis Apr 16 '16 at 09:18
  • As REST services should be stateless, I recommend using HTTP headers with every request. But if you want to have the same stateful behavior as before, I added more info into the answer about form-based authentication. The code example is an HTML form, but it should be easy to build the POST request in JavaScript. – OndroMih Apr 16 '16 at 10:25
  • Thank you again for your help OndrejM. Still having issues, but I really believe your first answer is the way to go. What this mean, I think, is that I really need to ask the question: "How do I set up my RESTful services in GlassFish such that it requires an Authorization token for each request?" I've been searching, but haven't come across a solid example of someone setting this up. Anyone out there know of such an example? – R. Purvis May 27 '16 at 10:59
  • Do you mean that your service is not secured and you can access it even without authentication? Then this is a completely different question than you've previously asked. Would you create a new question on SO and post here a link to it? I will then try to reply properly. – OndroMih May 27 '16 at 13:18
  • No, you can't currently access the service without authentication (see web.xml settings above). However, this leads to the 'issue' of only authenticating once per session, and each call not requiring authentication after that initial login. I will definitely submit a new question. As always, thank you for your help. – R. Purvis May 28 '16 at 10:18