(Release Candidate)
Copyright © 2015-2017 George Gaspar. All rights reserved.
Questions: igeorge1982@gmail.com
- upgrading to MySQL 8.0.26
- adding WildFly installation as back-up
- I have been developing this project for more than one year and finally I have come to the end of it. Although this project is not commercially licenced I would like to offer the chance to donate.
This project is about a login - registration system that can be used on WWW and iOS mobile and provides an authentication service and can be used as a Single-Sign-On service, as well, through desktop WWW, iOS mobile native, mobile WWW and mobile webview from native app because the user will have a token that will serve as the authenticator for restricted API calls.
The iOS swift code contains both type of login method from the native app, where the webview login serves as "ChangeUser" function.
The complete service system consists of several parts, layers that makes it easy to alter or extend the functionalities. The scope of the project is to demonstrate how the whole system works, starting from a user registration, user login, user accessing restricted data through authenticated API call, logout, timeout, simultenous user logins on different platforms, device login state tracking for native mobile app.
AES encryption - decryption is available across all platforms. For client specific instructions see the WWW readMe.
The server is also able verify the client's identity, as the most important thing to know is that who rings the bell on the door! :) For this purpose XSRF-TOKEN cookie is alos used on all platforms, which is generated on-the-fly with a data set that unanimously binds the client. The implemented behaviour is just an example as to how you are to send the cookie with the response, and there is a verification mechanism implemented, but how it shall work for one has the utmost unique requirements, so that you can make your own implementation. For example you may wish to store such informations in the cookie that comes with the initial request of the client and can assign it the session object as attribute, too, but you would be best off by adding another column into the table where you store your tokens and you can place your cookie value string to the corresponding row identified by the deviceId. Then you wish to read this value for each API calls and match the value of this cookie sent by the request with the one you have on the server. Since you can define and use multiple datastore for a given JPA - Hibernate project, it's not a big deal to use this authentication and authorization for separate datastores. Don't forget to overwrite the cookie value string when the session gets invalidated.
For more information on how it works: Angular’s XSRF: How It Works The most important thing is the Angular JS has a built-in support for the XSRF-Token meaning that with such name the cookie will be automatically sent by sub-sequent requests.
You can also add your own request / response filters to do the dirty job:
The universal implementation of Unix epoch time in all used languages made it available that all parts of the system can and does align to the elapsed time since 00:00:00 Coordinated Universal Time (UTC), Thursday, 1 January 1970 in the same format - LONG:
- Angular JS:
var microTime = new Date().getTime();
- Java:
System.currentTimeMillis();
SessionCreated = session.getCreationTime();
- Swift:
func getCurrentMillis()->Int64{
let time = Int64(NSDate().timeIntervalSince1970 * 1000)
return time
}
The general concept was to create an "entity" of a user that consists of username, uuid, password, device, voucher and login status (derived from the sessionid into the device_status table) in the context of the system. The main link should remian the uuid, I think.
The user object will be created by the following request:
Gateway/API/src/main/java/com/jeet/rest/BookController.java, line 68:
https://your_server.hu/{appName}/{contextPath}/{user}/{token1}"
that will be called by the following code in AdminServlet.java at line 169
RequestDispatcher rd = otherContext.getRequestDispatcher(webApiContextUrl + user.trim().toString()+"/"+token_.trim().toString());
The appName (or application context, which is also the base URI you define for JkMount) is defined in the pom.xml with artifactId and version nr (or finalName tag - POM Reference, if you prefer it that way), and contextPath is what you set up in your web.xml
<context-param>
<param-name>webApiContextUrl</param-name>
<param-value>/rest/user/</param-value>
</context-param>
You define the first part of the context in the web.xml for the API (Gateway/API/src/main/webapp/WEB-INF/web.xml):
<servlet-mapping>
<servlet-name>jersey</servlet-name>
<url-pattern>/rest/*</url-pattern>
</servlet-mapping>
One of the token parameter will be retrieved from the session, which will be the "user" attribute.
User has to provide the second key (token2) of tokens by a client request, which has to belong to the first one - retrieved from the session - by a given device.
There a websocket endpoint in the dalogin project com.websocket package to try out:
WebSocket is a full-duplex chanel for communication between client and server.
- WebSocket connection servlet and rabbitMQ send / recieve classes are included. The corresponding sample html and js file is included in the WWW app. You have to use a different secure port number on your AS for the wss connection, otherwise all the common servlet and JKMount configuration apply.
- WebSocket for iOS Swift: Starscream
rabbitMQ is a message publishing and subscribing system (or you can include the Apache Kafka Java clients, instead, or use both for your needs).
-
For authentication (index.html and register.html) Angular JS 1.3.x is used, because of the requestTransform funcionality.
-
Please note you would like to report issues you may find, so that I can fix that I might have missed.
- configure your links according to your environment setup (server, webApp, iOS)!
- for the APIs make sure you place the 'hibernate-configuration-3.0.dtd' file, found in dalogin (Gateway/dalogin/src/main/resources/) or API branch (Gateway/API/src/main/java/) of the project - or alternatively you can obtain one from the internet hibernate dtd -, to the configuration folder of your As. The 'hibernate.cfg.xml' can be configured to search for it locally or publically. Please refer to the Hibernate configurations! If you happened to forget to put the dtd file into the right folder upon the first corresponding request an exception will be thrown showing the path you must place the file to.
Public:
<<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"hibernate-configuration-3.0.dtd">
Local:
<!DOCTYPE hibernate-configuration SYSTEM
"http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
- make sure you will use your own application password for gmail sending. You can set up your configuration in the properties.properties file, now.
- as of Apple requirements https is required for server connections and it will be enforced as of 1st Jan 2017. Read more about app transport security: What's new in iOS 9, How to migrate to HTTPS using App Transport Security when developing iOS apps
- dB layer (MySQL 5.x<)
- (ORM) service model with Hibernate 5.x
- Data Access Object layer
- service methods that passes the DAO objects to the controller
- JAX-RS controller layer to provide HTTP methods
- TOMCAT 7, GlassFish 4 or wildFly 10.x servlet container as middleware component (Tomcat with crossContext enabled (required))
- APACHE httpd 2.2 server with mod_jk connector to front the application server with AJP (optional for load-balancing, otherwise you are supposed to use a webserver to properly access the header fields) -> alternatively you can use the Apache proxy modules, but I have not tested it.
Configured to run on SSL only, which is required as right now the iOS part is configured to use Certificate Authority (CA) -> Using Self-Signed SSL Certificates with iOS
The webserver and the application server is configured not to use cache, but it worked for me without cache settings, too!
- config files are included that you should use to get started.
- it facilitates AJP protocol with separate modjk configuration file (define a loadbalancer worker and assign its routes in the designated workers.properties file. For more info, pls see the corresponding Apache documentation!
- Apache Connectors and
- The Apache Tomcat Connectors - Web Server HowTo
- install openssl - for macOs you can use homebrew: brew install openssl
- build your Apache HTTP server with openssl and optionally apr included (you can use alternative installation solutions like homebrew, linux apt get install or specific to Windows)
- Apache Install,
- Compiling Apache for Microsoft Windows,
- Manual install on Windows 7 with Apache and MySQL
./configure \
--prefix=/opt/httpd \
--with-included-apr \
--enable-ssl \
--with-ssl=/opt/openssl-1.0.1i \
--enable-ssl-staticlib-deps \
--enable-mods-static=ssl
- install and enable mod_ssl - How To Install Apache 2 with SSL or
- may install openssl with homebrew on macOs
- add your SSL Certificate in httpd-ssl.conf (example included)
- add (compile/build/install) mod_jk pointing to your Apache installation like --with-apxs=/usr/sbin/apxs
- configure your mod_jk config file and include it in your httpd.conf file - Apache Tomcat mod_jk Connector Configuration , Configure Apache to load mod_jk
- reference your uriworkermap.properties in mod_jk config file (that is necesary, but actually we won't make use of it in this configuration)
- reference your workers.properties file in mod_jk config file and set up your workers
- the actual uri contexts (#JKMount paths with corresponding worker) are defined in httpd-ssl.conf in this configuration
- create your AJP listner with the same port in your AS (Tomcat, GlassFish - Tomcat server.xml Configuration Example, To Enable mod_jk on GlassFish, Enable SSL Between the mod_jk Load Balancer and GlassFish Server
- use Apache Tomcat 8.x< or WildFly with AJP port configured (you may use the WildFly installation from the gitHub repo)
- HTTP Strict Transport Security (HSTS) is a web security policy mechanism which helps to protect websites against protocol downgrade attacks and cookie hijacking. To complete the HSTS security you must obtain a trusted certificate from a Certificate Authority that can effectively verify your host.
Hardening Your HTTP Security Headers
- The in-memory session replication is tested with Apache Tomcat 8.x, following the official instructions. For Apache Tomcat the Cross context attribute is set to true.
- GlassFish and Wildfly settings will be included soon, but you can use a search engine to find it out
- Running cluster of Tomcat servers behind the Web server
- TomCat clustering and
- TomCat clustering
- TomCat Clustering How To
- the main config is set in the web.xml
- AS dependent settings (TomCat, GlassFish, Wildfly) must be implemented separately, with which you also have the ability to scale the resources needed for your system (only Tomcat provides built-in session persistence if you make your session attributes serializable). Please read through carefully the official documentations when configuring the ways of your session management. Basically, you can have three main options: in-memory, file store and database session persistance.
> The project uses and needs Java JDK 1.8.x ----
There are several solutions for Windows to use GlassFish or TomCat instance behind the IIS (Please note the how-to may differ based on the version of Windows. The links I supplied worked for me on Windows 10).
- The Apache Tomcat Connectors to IIS: ISAPI redirector for Micrsoft IIS HowTo
- Integrate Glassfish with IIS: How to Integrate Glassfish with IIS
- NHibernate is available as an object-relational mapping (ORM) solution for the Microsoft .NET platform.
- you will need to replace the jBoss logging jar to the newest version because the Hibernate is dependent on it, but there are GlassFish versions that do not include the correct version. You will find this particular jar here in GLASSFISH_HOME/glassfish/modules, and then also insert a new logger at the server console referencing this logger NoSuchMethodError. You may need to restart your computer for the changes to take effect.
- as for the server part can be deployed as it is, just take care of the web.xml. The current configuration shall work without modification.
- as for WWW platform deploy directly the angular js web app onto TOMCAT or GlassFish to your preferred context (Note: the AngularJS is the preferred and tested, only). If you use wildFly then you must deploy the application with Create an unmanaged deployment option. For wildFly see the wildFly instructions
- as for iOS build the project and you can use the registration/login service in native way or through webview, too. The registration without voucher is not implemented yet fully, but will work the same way as the login, just skip the related parts.
The project contains the source code of the whole system in the dedicated branch leaf.
Import the project as Existing Maven project into your Java IDE (Eclipse) and run Maven Install.
If you just want to compile, and don't make a war, use the following command:
mvn dependency:copy-dependencies -Dmaven.test.skip=true compile
All the sql scripts should run flawlessly. If not, check your schema, user, etc. The sql script files are a result of dumping my working schema.
- you may have to remove the NO_AUTO_CREATE_USER lines from the dump script, or whatever the MySql Workbench consol says as error
- Create your schema first, then run the dB dump scripts to create the dB tables
- Create the dB user for the application
- Insert initial vouchers, with activation flags set, into the voucher_states table, if you want to have registration, or just put a username and a hashed password (with the same hashing algorithm that you selected in your client apps - if you had made any changes to the code base) into the logins table.
- Registration workflow is implemented with or without voucher and activation
- Unique username and email checking is done by the underlying dB, and the supplied API will perform the check, only, without enforcement.
- The servlet context also makes it available to check the active users with a designated API call. You can found it in the simple-service-webapp
After you have built and deployed all parts (web app, iOS) of the service, you have to be able to access the site and use the system. Start registration process and the login through WWW (mobile, too), native iOS and iOS webview from the app.
- For registration you need to provide a preset and available voucher, username, email and password. After having successfully registered or logged in, you will receive a token part that you need to use for API calls. Upon each login you will receive a new token part. You will find examples in the example database.
- Based on which type of registration you have implemented you may need to activate a voucher to access the restricted API. You can send an email to the email address you have given during the registration. (Registration without voucher workflow is supplied in the code base, however it may not be fully functional as I did some changes recently.) It is not the scope of the project to go beyond successfully recieving the response through the restricted API call, so voucher activation will not be implemented neither the registration through webview. Your part comes in to extend the code.
- For login you need to provide a valid username and password. The password is immediately transformed using sha3 hashing algoritm and that will be stored in the database. The password is a field of char type in the database.
- After your session has been invalidated you will not be able to access the user data through the designated API call because that requires a valid token part to authenticate (once the session has been invalidated, the token will be overwritten automatically on the server, therefor the client will not know it!). You will recieve an error message when trying to access restricted data after session invalidation.
- there is a parameter in the web.xml that sets the time intervallum for the requests to be completed. This feature has been added only for performance testing purposes.
-
authentication will happen with user supplied and system generated data on the front-end that will have to match on the server where these data will be re-generated and validated. For this purpose HMAC (hashed message authentication) is used. The hmac signature will be generated on the fly before the client sends out the request. Basically the hmac will take all the necessary arguments and then will create the signature that will be regenerated on the server with the same arguments. Because the server has fix string parameters along with the supplied arguments, it can work as a secure tool to verify the request and the integrity of the data in the request the came through the internet.
-
For more information on hmac interoperabilty: hmac interoperability for multiple systems.
-
With great effort put into work on iOS the deviceId will be the real ID of the iPhone device. This is a very important step in providing the ability to have the actual device ID that we can track in all cases regardless the user logs in through native authentication, or the webview from the native app. To track a WWW and mobile WWW device login state have never been in scope.
- there are four tables that are very sensitive and if you modify them separately unexpected behaviour may occur: Last_seen, Tokens, device_states, devices.
- if you want to clear / clean up the dB or of devices, but not of the user, because something went wrong, you need to truncate all the following tables: Last_seen, Tokens, device_states, devices.
It uses the WKWebView, that passes the cookies to the shared cookie storage.
Last update: 2021.09.06.
Copyright © 2015-2021 George Gaspar. All rights reserved.