Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Appearance settings
This repository was archived by the owner on Jan 25, 2019. It is now read-only.
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
af3e2a4
Add Java EE Security 1.0 API examples
Aug 23, 2017
2298932
Add example demonstrating custom identity store
Aug 27, 2017
0db26a0
Add custom_identity_store module
Aug 27, 2017
b22fa1f
Incorporate review comments
Sep 1, 2017
0e67b0a
Update copyright
Sep 1, 2017
51485be
Incorporate review comments
Sep 4, 2017
aaf0623
add resource element
Sep 12, 2017
4a03b38
[maven-release-plugin] rollback the release of 8.0
Sep 12, 2017
28c7cc8
add empty
Sep 12, 2017
30bf5ce
add empty file to ear projects
Sep 12, 2017
2c21f33
Update security-api version
Sep 12, 2017
1f559d8
Merge remote-tracking branch 'upstream/master' into javaee-security-e…
Sep 12, 2017
dfa9c53
add empty file to simple-flow
Sep 12, 2017
f5eabe7
[maven-release-plugin] prepare release 8.0
Sep 12, 2017
84eae93
[maven-release-plugin] prepare for next development iteration
Sep 12, 2017
4383a56
[maven-release-plugin] rollback the release of 8.0
Sep 12, 2017
f0e034a
release script changes
Sep 12, 2017
bb5b63d
[maven-release-plugin] prepare release 8.0
Sep 15, 2017
9e9cf5e
[maven-release-plugin] rollback the release of 8.0
Sep 15, 2017
587ef36
[maven-release-plugin] prepare release 8.0
Sep 15, 2017
ae6c056
[maven-release-plugin] prepare for next development iteration
Sep 15, 2017
305f038
updated copyright year
jruzzi Sep 18, 2017
dcd25b5
change back to 8.0-SNAPSHOT
Sep 20, 2017
79018e1
Add Java EE Security 1.0 API examples
Aug 23, 2017
00b86c4
Add example demonstrating custom identity store
Aug 27, 2017
9bd790d
Add custom_identity_store module
Aug 27, 2017
4805606
Incorporate review comments
Sep 1, 2017
009a6a9
Update copyright
Sep 1, 2017
14b6e3d
Incorporate review comments
Sep 4, 2017
3a19bb0
add resource element
Sep 12, 2017
6a6f123
[maven-release-plugin] rollback the release of 8.0
Sep 12, 2017
0f5de90
add empty
Sep 12, 2017
284ff83
Update security-api version
Sep 12, 2017
865a525
Update version
Sep 20, 2017
0b9d287
Remove promoted repo details
Sep 20, 2017
44aac95
Update version
Sep 20, 2017
e4b47f0
Resolve merge conflicts
Sep 20, 2017
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion 2 LICENSE.txt
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
Copyright 2014 Oracle and/or its affiliates. All rights reserved. Use is
Copyright 2017 Oracle and/or its affiliates. All rights reserved. Use is
subject to license terms.

Redistribution and use in source and binary forms, with or without
Expand Down
1 change: 1 addition & 0 deletions 1 connectors/traffic/traffic-ear/src/main/resources/empty
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@

3 changes: 2 additions & 1 deletion 3 pom.xml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">

<modelVersion>4.0.0</modelVersion>
<parent>
Expand All @@ -15,6 +15,7 @@
<scm>
<connection>scm:git:https://github.com/javaee/tutorial-examples.git</connection>
<developerConnection>scm:git:git@github.com:javaee/tutorial-examples.git</developerConnection>
<tag>HEAD</tag>
</scm>
<issueManagement>
<system>GitHub</system>
Expand Down
3 changes: 1 addition & 2 deletions 3 release.sh
Original file line number Diff line number Diff line change
Expand Up @@ -76,5 +76,4 @@ ARGS=" $*"
# everything supplied as argument will be provided to every maven command.
# e.g to supply -Dmaven.skip.test or -Dmaven.repo.local=/path/to/repo

mvn -B -e release:prepare -DpreparationGoals="package $ARGS" -Prelease
mvn -B -e release:perform -Prelease
mvn -B -e release:prepare -DpreparationGoals="package" -DuseDefaultManifestFile=true
1 change: 1 addition & 0 deletions 1 security/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
<module>converter-secure</module>
<module>hello1-formauth</module>
<module>hello2-basicauth</module>
<module>security-api</module>
</modules>

<build>
Expand Down
227 changes: 227 additions & 0 deletions 227 security/security-api/built-in-db-identity-store/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
# Built-in Database Identity Store
JSR 375 mandates that a Java EE container MUST support built-in `IdentityStore` backed by a database.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might want to use the LdapIdentityStore provider instead of database, as this will be a more common case.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree, may be I will try to include LdapIdentityStore one as a seperate example and retain this one as well.


To support this mandatory requirement, `DatabaseIdentityStore` comes bundled with GlassFish-RI.

This example demonstrates how you can configure a `DatabaseIdentityStore` to point to a backend database and then use it as an `IdentityStore`.

In this example, the following users are defined, along with the groups they are in.

|User|Password|Group|
|----|--------|----|
|Joe|secret1|foo,bar|
|Sam|secret2|foo,bar|
|Tom|secret2|foo|
|Sue|secret2|foo|

When a request is made to the application with certain credentials, the authentication mechanism bundled with this application comes into effect and authentication is performed against the `DatabaseIdentityStore` as defined in the application.

Post authentication, the application also verifies the roles the caller is in and sends the details as part of the response.

How to define credentials and the roles assigned to users is shown below:

```java

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.SQLException;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import javax.annotation.sql.DataSourceDefinition;
import javax.ejb.Singleton;
import javax.ejb.Startup;
import javax.sql.DataSource;

@Singleton
@Startup
public class DatabaseSetup {

// The default datasource that is bundled with GlassFish is used to store // credentials.
@Resource(lookup="java:comp/DefaultDataSource")
private DataSource dataSource;

@PostConstruct
public void init() {

// ...
executeUpdate(dataSource, "INSERT INTO caller VALUES('Joe', '" + passwordHash.generate("secret1".toCharArray()) + "')");
// ...
executeUpdate(dataSource, "INSERT INTO caller_groups VALUES('Joe', 'foo')");
executeUpdate(dataSource, "INSERT INTO caller_groups VALUES('Joe', 'bar')");
// ...
}

@PreDestroy
public void destroy() {
// ...
}

private void executeUpdate(DataSource dataSource, String query) {
// ...
}
}

```
With `@Startup` annotation, this singleton enterprise bean is initialized during application startup and the credentials are set in the underlying database.

Built-in `DatabaseIdentityStore` gets mapped with the `DefaultDataSource` by defining the `ApplicationConfig` with the help of `@DatabaseIdentityStoreDefinition`.

```java
// Database Definition for built-in DatabaseIdentityStore
@DatabaseIdentityStoreDefinition(
callerQuery = "#{'select password from caller where name = ?'}",
groupsQuery = "select group_name from caller_groups where caller_name = ?",
hashAlgorithm = Pbkdf2PasswordHash.class,
priorityExpression = "#{100}",
hashAlgorithmParameters = {
"Pbkdf2PasswordHash.Iterations=3072",
"${applicationConfig.dyna}"
}
)

@ApplicationScoped
@Named
public class ApplicationConfig {

public String[] getDyna() {
return new String[]{"Pbkdf2PasswordHash.Algorithm=PBKDF2WithHmacSHA512", "Pbkdf2PasswordHash.SaltSizeBytes=64"};
}

}
```
In this application, we are validating credentials using BASIC authentication mechanism. Following annotation in `ApplicationConfig` ensures that the `BasicAuthenticationMechanism` is used to perform credential validation.

```java
@BasicAuthenticationMechanismDefinition(
realmName = "file"
)
```

Please note that in GlassFish, when BasicAuthenticationMechanism is used as the authentication mechanism, the `realmName` basically is presented to user ,as a hint, when wrong credentials are provided by the user.


```bash
curl -I -u Joe http://localhost:8080/built-in-db-identity-store/servlet
Enter host password for user 'Joe':
HTTP/1.1 401 Unauthorized
Server: GlassFish Server Open Source Edition 5.0
X-Powered-By: Servlet/3.1 JSP/2.3 (GlassFish Server Open Source Edition 5.0 Java/Oracle Corporation/1.8)
WWW-Authenticate: Basic realm="file"
Content-Length: 1090
Content-Language:
Content-Type: text/html
```

When a request is made to the application, the roles the user is in get returned as part of the repsonse.

```java
@WebServlet("/servlet")
@DeclareRoles({ "foo", "bar", "kaz" })
@ServletSecurity(@HttpConstraint(rolesAllowed = "foo"))
public class Servlet extends HttpServlet {

private static final long serialVersionUID = 1L;

@Override
public void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {

String webName = null;
if (request.getUserPrincipal() != null) {
webName = request.getUserPrincipal().getName();
}

response.getWriter().write("web username: " + webName + "\n");

response.getWriter().write("web user has role \"foo\": " + request.isUserInRole("foo") + "\n");
response.getWriter().write("web user has role \"bar\": " + request.isUserInRole("bar") + "\n");
response.getWriter().write("web user has role \"kaz\": " + request.isUserInRole("kaz") + "\n");
}

}
```
Note that the container needs to be made aware of the supported roles, which is achieved with the help of `@DeclareRoles` annotation as shown above.

```java
@DeclareRoles({ "foo", "bar", "kaz" })
```
In GlassFish 5.0, role to group mapping is enabled by default. Therefore, you do not need to bundle `web.xml` with the application to provide mapping between roles and groups.

In this example, we are using the credentials of user `Joe` to make a request and validate the response according to the credentials/roles defined in `DatabaseSetup.java` above.

**Steps:**

* Since we are using the default datasource bundled with GlassFish for `DatabaseIdentityStore`, start the default database by running the following command:

`asadmin start-database`

* Start the domain

`asadmin start-domain`

* Deploy the application

`asadmin deploy <project>/target/built-in-db-identity-store.war`

After the application is deployed, we can make a request to the application using the URL shown below:

---

**Request URL:**

```bash
http://localhost:8080/built-in-db-identity-store/servlet
```

Since BASIC authentication is being used here, the container responds back prompting for username and password.

Once username and password are provided, the client presents the request to conainer with base64 encoded string and with `Authorization` header having value in the format expected for basic authentication.

With username and password available to the container, the validation is then done against `DatabaseIdentityStore`.

The corresponding `UsernamePasswordCredential` object is passed as parameter to `DatabaseIdentityStore#validate()` method.

Password is then fetched from database for user `Joe`. The password stored in database is hashed using `PBKDF2` algorithm. The password is then verified by built-in `Pbkdf2PasswordHash` implementation.

On successful verification, the request finally gets delegated to the servlet in question and response is returned to the end user.

**Response:**

```bash
web username: Joe
web user has role "foo": true
web user has role "bar": true
web user has role "kaz": false
```
---

**If invalid credentials are used:**

---

**Request URL:**

```bash
http://localhost:8080/built-in-db-identity-store/servlet
```

**Response:**


**`HTTP Status 401 - Unauthorized`**

**`type`** `Status report`

**`message`** `Unauthorized`

**`description`** `This request requires HTTP authentication.`

**`GlassFish Server Open Source Edition 5`**

---

In this application, we are using BasicAuthenticationMechanism.

When a request is made to the servlet in question,
container delegates the request to `org.glassfish.soteria.mechanisms.jaspic.HttpBridgeServerAuthModule`, which then invokes BasicAuthenticationMechanism#validateRequest method, and gets the credential from the request.
31 changes: 31 additions & 0 deletions 31 security/security-api/built-in-db-identity-store/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>

<parent>
<groupId>org.glassfish.javaeetutorial</groupId>
<artifactId>security-api</artifactId>
<version>8.0-SNAPSHOT</version>
</parent>

<artifactId>built-in-db-identity-store</artifactId>
<packaging>war</packaging>

<build>
<finalName>built-in-db-identity-store</finalName>
</build>

<properties>
<failOnMissingWebXml>false</failOnMissingWebXml>
</properties>

<dependencies>
<dependency>
<groupId>javax.security.enterprise</groupId>
<artifactId>javax.security.enterprise-api</artifactId>
<version>1.0</version>
<scope>provided</scope>
</dependency>
</dependencies>

</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
/**
* Copyright (c) 2017 Oracle and/or its affiliates. All rights reserved.
*
* You may not modify, use, reproduce, or distribute this software except in
* compliance with the terms of the License at:
* https://github.com/javaee/tutorial-examples/LICENSE.txt
*/

package javaeetutorial.built_in_db_identity_store;

import javax.enterprise.context.ApplicationScoped;
import javax.inject.Named;
import javax.security.enterprise.authentication.mechanism.http.BasicAuthenticationMechanismDefinition;
import javax.security.enterprise.identitystore.DatabaseIdentityStoreDefinition;
import javax.security.enterprise.identitystore.Pbkdf2PasswordHash;

// Database Definition for built-in DatabaseIdentityStore
@DatabaseIdentityStoreDefinition(
callerQuery = "#{'select password from caller where name = ?'}",
groupsQuery = "select group_name from caller_groups where caller_name = ?",
hashAlgorithm = Pbkdf2PasswordHash.class,
priorityExpression = "#{100}",
hashAlgorithmParameters = {
"Pbkdf2PasswordHash.Iterations=3072",
"${applicationConfig.dyna}"
}
)

@BasicAuthenticationMechanismDefinition(
realmName = "file"
)

@ApplicationScoped
@Named
public class ApplicationConfig {

public String[] getDyna() {
return new String[]{"Pbkdf2PasswordHash.Algorithm=PBKDF2WithHmacSHA512", "Pbkdf2PasswordHash.SaltSizeBytes=64"};
}

}
Loading
Morty Proxy This is a proxified and sanitized view of the page, visit original site.