Skip to content

Commit

Permalink
changed the basic auth jdbc validator to use the new jdbc component
Browse files Browse the repository at this point in the history
  • Loading branch information
EricWittmann committed Nov 11, 2015
1 parent 729a6fc commit ceafc25
Show file tree
Hide file tree
Showing 5 changed files with 109 additions and 46 deletions.
Expand Up @@ -51,7 +51,7 @@ public interface IJdbcResultSet {
/**
* Point at next row in result set
*/
void next();
boolean next();

/**
* Indicates whether there is another row in the results
Expand Down
Expand Up @@ -84,11 +84,12 @@ public int getRow() {
* @see io.apiman.gateway.engine.components.jdbc.IJdbcResultSet#next()
*/
@Override
public void next() {
public boolean next() {
try {
resultSet.next();
return resultSet.next();
} catch (SQLException e) {
e.printStackTrace();
return false;
}
}

Expand Down
Expand Up @@ -16,16 +16,17 @@
package io.apiman.gateway.engine.policies.auth;

import io.apiman.gateway.engine.async.AsyncResultImpl;
import io.apiman.gateway.engine.async.IAsyncResult;
import io.apiman.gateway.engine.async.IAsyncResultHandler;
import io.apiman.gateway.engine.beans.ServiceRequest;
import io.apiman.gateway.engine.components.jdbc.IJdbcClient;
import io.apiman.gateway.engine.components.jdbc.IJdbcComponent;
import io.apiman.gateway.engine.components.jdbc.IJdbcConnection;
import io.apiman.gateway.engine.components.jdbc.IJdbcResultSet;
import io.apiman.gateway.engine.policies.AuthorizationPolicy;
import io.apiman.gateway.engine.policies.config.basicauth.JDBCIdentitySource;
import io.apiman.gateway.engine.policy.IPolicyContext;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.HashSet;
import java.util.Set;

Expand Down Expand Up @@ -54,7 +55,9 @@ public JDBCIdentityValidator() {
*/
@Override
public void validate(String username, String password, ServiceRequest request, IPolicyContext context,
JDBCIdentitySource config, IAsyncResultHandler<Boolean> handler) {
JDBCIdentitySource config, final IAsyncResultHandler<Boolean> handler) {
IJdbcComponent jdbcComponent = context.getComponent(IJdbcComponent.class);

DataSource ds = null;
try {
ds = lookupDatasource(config);
Expand Down Expand Up @@ -83,49 +86,102 @@ public void validate(String username, String password, ServiceRequest request, I
default:
break;
}
String query = config.getQuery();
Connection conn = null;
boolean validated = false;
try {
// Get a JDBC connection
conn = ds.getConnection();
conn.setReadOnly(true);
final String query = config.getQuery();
final String queryUsername = username;
final String queryPassword = sqlPwd;

IJdbcClient client = jdbcComponent.create(ds);
client.connect(new IAsyncResultHandler<IJdbcConnection>() {
@Override
public void handle(IAsyncResult<IJdbcConnection> result) {
if (result.isError()) {
handler.handle(AsyncResultImpl.create(result.getError(), Boolean.class));
} else {
validate(result.getResult(), query, queryUsername, queryPassword, context, config, handler);
}
}
});
}

// Validate the user exists and the password matches.
PreparedStatement statement = conn.prepareStatement(query);
statement.setString(1, username);
statement.setString(2, sqlPwd);
ResultSet resultSet = statement.executeQuery();
if (resultSet.next()) {
validated = true;
/**
* @param connection
* @param query
* @param username
* @param context
* @param password
* @param config
* @param handler
*/
protected void validate(final IJdbcConnection connection, final String query, final String username,
final String password, final IPolicyContext context, final JDBCIdentitySource config,
final IAsyncResultHandler<Boolean> handler) {
IAsyncResultHandler<IJdbcResultSet> queryHandler = new IAsyncResultHandler<IJdbcResultSet>() {
@Override
public void handle(IAsyncResult<IJdbcResultSet> result) {
if (result.isError()) {
closeQuietly(connection);
handler.handle(AsyncResultImpl.create(result.getError(), Boolean.class));
} else {
boolean validated = false;
IJdbcResultSet resultSet = result.getResult();
if (resultSet.next()) {
validated = true;
}
resultSet.close();
if (validated && config.isExtractRoles()) {
extractRoles(connection, username, context, config, handler);
} else {
closeQuietly(connection);
handler.handle(AsyncResultImpl.create(validated));
}
}
}
resultSet.close();
statement.close();
};
connection.query(queryHandler, query, username, password);
}

// Extract roles from the DB
if (config.isExtractRoles()) {
statement = conn.prepareStatement(config.getRoleQuery());
statement.setString(1, username);
resultSet = statement.executeQuery();
Set<String> extractedRoles = new HashSet<>();
while (resultSet.next()) {
String roleName = resultSet.getString(1);
extractedRoles.add(roleName);
/**
* @param connection
* @param username
* @param context
* @param config
* @param handler
*/
protected void extractRoles(final IJdbcConnection connection, final String username,
final IPolicyContext context, final JDBCIdentitySource config,
final IAsyncResultHandler<Boolean> handler) {

String roleQuery = config.getRoleQuery();
IAsyncResultHandler<IJdbcResultSet> roleHandler = new IAsyncResultHandler<IJdbcResultSet>() {
@Override
public void handle(IAsyncResult<IJdbcResultSet> result) {
if (result.isError()) {
closeQuietly(connection);
handler.handle(AsyncResultImpl.create(result.getError(), Boolean.class));
} else {
Set<String> extractedRoles = new HashSet<>();
IJdbcResultSet resultSet = result.getResult();
while (resultSet.next()) {
String roleName = resultSet.getString(1);
extractedRoles.add(roleName);
}
context.setAttribute(AuthorizationPolicy.AUTHENTICATED_USER_ROLES, extractedRoles);
closeQuietly(connection);
handler.handle(AsyncResultImpl.create(true));
}
resultSet.close();
statement.close();
// Save the extracted roles to the policy context for use by e.g.
// the Authorization policy (if configured).
context.setAttribute(AuthorizationPolicy.AUTHENTICATED_USER_ROLES, extractedRoles);
}
};
connection.query(roleHandler, roleQuery, username);
}

handler.handle(AsyncResultImpl.create(validated));
/**
* @param connection
*/
protected void closeQuietly(IJdbcConnection connection) {
try {
connection.close();
} catch (Exception e) {
handler.handle(AsyncResultImpl.create(e, Boolean.class));
} finally {
if (conn != null) {
try { conn.close(); } catch (SQLException e) { }
}
// TODO log this error
}
}

Expand Down
Expand Up @@ -19,6 +19,8 @@
import io.apiman.gateway.engine.beans.PolicyFailureType;
import io.apiman.gateway.engine.beans.ServiceRequest;
import io.apiman.gateway.engine.components.IPolicyFailureFactoryComponent;
import io.apiman.gateway.engine.components.jdbc.IJdbcComponent;
import io.apiman.gateway.engine.impl.DefaultJdbcComponent;
import io.apiman.gateway.engine.policies.config.BasicAuthenticationConfig;
import io.apiman.gateway.engine.policy.IPolicyChain;
import io.apiman.gateway.engine.policy.IPolicyContext;
Expand Down Expand Up @@ -94,6 +96,7 @@ public PolicyFailure createFailure(PolicyFailureType type, int failureCode, Stri
return failure;
}
});
Mockito.when(context.getComponent(IJdbcComponent.class)).thenReturn(new DefaultJdbcComponent());
IPolicyChain<ServiceRequest> chain = Mockito.mock(IPolicyChain.class);

// Failure
Expand Down Expand Up @@ -139,6 +142,7 @@ public void testApplyJdbcWithRoles() throws Exception {
request.setRemoteAddr("1.2.3.4");
request.setDestination("/");
IPolicyContext context = Mockito.mock(IPolicyContext.class);
Mockito.when(context.getComponent(IJdbcComponent.class)).thenReturn(new DefaultJdbcComponent());
IPolicyChain<ServiceRequest> chain = Mockito.mock(IPolicyChain.class);

// Success
Expand Down
Expand Up @@ -68,12 +68,14 @@ protected int getNumRows() {
return resultSet.getNumRows();
}

/* (non-Javadoc)
/**
* @see io.apiman.gateway.engine.components.jdbc.IJdbcResultSet#next()
*/
@Override
public void next() {
public boolean next() {
boolean isok = hasNext();
row += 1;
return isok;
}

/* (non-Javadoc)
Expand Down

0 comments on commit ceafc25

Please sign in to comment.