Skip to content

Commit

Permalink
Merge branch 'dev' into multiple-public-keys-and-ecdsa-signature
Browse files Browse the repository at this point in the history
# Conflicts:
#	src/main/java/org/radarcns/management/config/OAuth2ServerConfiguration.java
  • Loading branch information
dennyverbeeck committed Jul 10, 2018
2 parents 0164a17 + 6b843e8 commit c5bee2f
Show file tree
Hide file tree
Showing 35 changed files with 504 additions and 87 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -71,7 +71,7 @@ memory database and ManagementPortal.



The docker image can be pulled by running `docker pull radarcns/management-portal:0.3.7
The docker image can be pulled by running `docker pull radarcns/management-portal:0.3.8

## Configuration

Expand Down
4 changes: 2 additions & 2 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,8 @@ plugins {
allprojects {
group 'org.radarcns'

version '0.3.8-SNAPSHOT' // project version
version '0.3.9-SNAPSHOT' // project version

// The comment on the previous line is only there to identify the project version line easily
// with a sed command, to auto-update the version number with the prepare-release-branch.sh
// script, do not remove it.
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ metrics_spring_version=3.1.3
node_version=6.10.0
npm_version=4.3.0
prometheus_simpleclient_version=0.0.20
postgresql_version=9.4.1212
postgresql_version=42.2.2
spring_security_oauth2_version=2.2.1.RELEASE
springfox_version=2.6.1
spring_boot_version=1.5.9.RELEASE
Expand Down
2 changes: 1 addition & 1 deletion oauth-client-util/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Quickstart:

```groovy
dependencies {
compile group: 'org.radarcns', name: 'oauth-client-util', version: '0.3.7'
compile group: 'org.radarcns', name: 'oauth-client-util', version: '0.3.8'
}
```

Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "management-portal",
"version": "0.3.8-SNAPSHOT",
"version": "0.3.8",
"description": "Description for ManagementPortal",
"private": true,
"cacheDirectories": [
Expand Down
2 changes: 1 addition & 1 deletion radar-auth/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Add the dependency to your project.

Gradle:
```groovy
compile group: 'org.radarcns', name: 'radar-auth', version: '0.3.7'
compile group: 'org.radarcns', name: 'radar-auth', version: '0.3.8'
```

The library expects the identity server configuration in a file called `radar-is.yml`. Either set
Expand Down
2 changes: 1 addition & 1 deletion src/main/docker/etc/config/oauth_client_details.csv
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,4 @@ aRMT;res_ManagementPortal,res_gateway;secret;MEASUREMENT.CREATE,SUBJECT.UPDATE,S
THINC-IT;res_ManagementPortal,res_gateway;secret;MEASUREMENT.CREATE,SUBJECT.UPDATE,SUBJECT.READ,PROJECT.READ,SOURCETYPE.READ,SOURCE.READ,SOURCETYPE.READ,SOURCEDATA.READ,USER.READ,ROLE.READ;refresh_token,authorization_code;;;43200;7948800;{"dynamic_registration": true};
radar_restapi;res_ManagementPortal;secret;SUBJECT.READ,PROJECT.READ,SOURCE.READ,SOURCETYPE.READ;client_credentials;;;43200;259200;{};
radar_redcap_integrator;res_ManagementPortal;secret;PROJECT.READ,SUBJECT.CREATE,SUBJECT.READ,SUBJECT.UPDATE;client_credentials;;;43200;259200;{};
radar_dashboard;res_ManagementPortal,res_RestApi;secret;SUBJECT.READ,PROJECT.READ,SOURCE.READ,SOURCETYPE.READ;client_credentials;;;43200;259200;{};
radar_dashboard;res_ManagementPortal,res_RestApi;secret;SUBJECT.READ,PROJECT.READ,SOURCE.READ,SOURCETYPE.READ;refresh_token,authorization_code;;;43200;259200;{};
2 changes: 1 addition & 1 deletion src/main/docker/management-portal.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
version: '2'
services:
managementportal-app:
image: radarcns/management-portal:0.3.7
image: radarcns/management-portal:0.3.8
environment:
- SPRING_PROFILES_ACTIVE=prod,swagger
- SPRING_DATASOURCE_URL=jdbc:postgresql://managementportal-postgresql:5432/managementportal
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,14 @@
import io.github.jhipster.security.Http401UnauthorizedEntryPoint;
import org.radarcns.auth.authorization.AuthoritiesConstants;
import org.radarcns.management.security.ClaimsTokenEnhancer;
import org.radarcns.management.security.PostgresApprovalStore;
import org.radarcns.management.security.jwt.EcdsaVerifier;
import org.radarcns.management.security.jwt.MultiVerifier;
import org.radarcns.management.security.jwt.RadarJwtAccessTokenConverter;
import org.radarcns.management.security.jwt.RadarKeyStoreKeyFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.autoconfigure.orm.jpa.JpaProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
Expand Down Expand Up @@ -56,6 +58,8 @@
import java.util.List;
import java.util.stream.Collectors;

import static org.springframework.orm.jpa.vendor.Database.POSTGRESQL;

@Configuration
public class OAuth2ServerConfiguration {

Expand Down Expand Up @@ -167,6 +171,9 @@ public void publishAuthenticationSuccess(Authentication authentication) {
protected static class AuthorizationServerConfiguration extends
AuthorizationServerConfigurerAdapter {

@Autowired
private JpaProperties jpaProperties;

@Autowired
@Qualifier("authenticationManagerBean")
private AuthenticationManager authenticationManager;
Expand All @@ -187,7 +194,12 @@ protected AuthorizationCodeServices authorizationCodeServices() {

@Bean
public ApprovalStore approvalStore() {
return new JdbcApprovalStore(dataSource);
if (jpaProperties.getDatabase().equals(POSTGRESQL)) {
return new PostgresApprovalStore(dataSource);
} else {
// to have compatibility for other databases including H2
return new JdbcApprovalStore(dataSource);
}
}

@Bean
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
package org.radarcns.management.hibernate;

import org.hibernate.engine.jdbc.env.spi.JdbcEnvironment;
import org.springframework.boot.orm.jpa.hibernate.SpringPhysicalNamingStrategy;

public class CaseSensitivePhysicalNamingStrategy extends SpringPhysicalNamingStrategy {

@Override
protected boolean isCaseInsensitive(JdbcEnvironment jdbcEnvironment) {
return false;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
/*
* Copyright 2012-2013 the original author or authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.radarcns.management.security;

import static org.springframework.security.oauth2.provider.approval.Approval.ApprovalStatus.APPROVED;

import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Timestamp;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import javax.sql.DataSource;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.dao.DataAccessException;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;
import org.springframework.security.oauth2.provider.approval.Approval;
import org.springframework.security.oauth2.provider.approval.Approval.ApprovalStatus;
import org.springframework.security.oauth2.provider.approval.ApprovalStore;
import org.springframework.util.Assert;

/**
* This class will be used to execute functions related to token approval. It is an duplicate of
* JdbcApprovalStore with escaped case sensitive fields to query.
*
* @author Dave Syer
* @author Modified by Nivethika
*/
public class PostgresApprovalStore implements ApprovalStore {

private final JdbcTemplate jdbcTemplate;

private final Logger logger = LoggerFactory.getLogger(PostgresApprovalStore.class);

private final RowMapper<Approval> rowMapper = new AuthorizationRowMapper();

private static final String TABLE_NAME = "oauth_approvals";

private static final String FIELDS =
"\"expiresAt\", \"status\",\"lastModifiedAt\",\"userId\"," + "\"clientId\","
+ "\"scope\"";

private static final String WHERE_KEY = "where \"userId\"=? and \"clientId\"=?";

private static final String WHERE_KEY_AND_SCOPE = WHERE_KEY + " and \"scope\"=?";

private static final String AND_LESS_THAN_EXPIRE_AT = " and \"expiresAt\" <= ?";

private static final String DEFAULT_ADD_APPROVAL_STATEMENT =
String.format("insert into %s ( %s ) values (?,?,?,?,?,?)", TABLE_NAME, FIELDS);

private static final String DEFAULT_REFRESH_APPROVAL_STATEMENT = String.format(
"update %s set \"expiresAt\"=?, \"status\"=?, \"lastModifiedAt\"=? "
+ WHERE_KEY_AND_SCOPE, TABLE_NAME);

private static final String DEFAULT_GET_APPROVAL_SQL =
String.format("select %s from %s " + WHERE_KEY, FIELDS, TABLE_NAME);

private static final String DEFAULT_DELETE_APPROVAL_SQL =
String.format("delete from %s " + WHERE_KEY_AND_SCOPE + AND_LESS_THAN_EXPIRE_AT,
TABLE_NAME);

private static final String DEFAULT_EXPIRE_APPROVAL_STATEMENT =
String.format("update %s set " + "\"expiresAt\" = ? "
+ WHERE_KEY_AND_SCOPE, TABLE_NAME);

private String addApprovalStatement = DEFAULT_ADD_APPROVAL_STATEMENT;

private String refreshApprovalStatement = DEFAULT_REFRESH_APPROVAL_STATEMENT;

private String findApprovalStatement = DEFAULT_GET_APPROVAL_SQL;

private String deleteApprovalStatment = DEFAULT_DELETE_APPROVAL_SQL;

private String expireApprovalStatement = DEFAULT_EXPIRE_APPROVAL_STATEMENT;

private boolean handleRevocationsAsExpiry = false;

public PostgresApprovalStore(DataSource dataSource) {
Assert.notNull(dataSource);
this.jdbcTemplate = new JdbcTemplate(dataSource);
}

public void setHandleRevocationsAsExpiry(boolean handleRevocationsAsExpiry) {
this.handleRevocationsAsExpiry = handleRevocationsAsExpiry;
}

public void setAddApprovalStatement(String addApprovalStatement) {
this.addApprovalStatement = addApprovalStatement;
}

public void setFindApprovalStatement(String findApprovalStatement) {
this.findApprovalStatement = findApprovalStatement;
}

public void setDeleteApprovalStatment(String deleteApprovalStatment) {
this.deleteApprovalStatment = deleteApprovalStatment;
}

public void setExpireApprovalStatement(String expireApprovalStatement) {
this.expireApprovalStatement = expireApprovalStatement;
}

public void setRefreshApprovalStatement(String refreshApprovalStatement) {
this.refreshApprovalStatement = refreshApprovalStatement;
}

@Override
public boolean addApprovals(final Collection<Approval> approvals) {
logger.debug(String.format("adding approvals: [%s]", approvals));
boolean success = true;
for (Approval approval : approvals) {
if (!updateApproval(refreshApprovalStatement, approval) && !updateApproval(
addApprovalStatement, approval)) {
success = false;
}
}
return success;
}

@Override
public boolean revokeApprovals(Collection<Approval> approvals) {
logger.debug(String.format("Revoking approvals: [%s]", approvals));
boolean success = true;
for (final Approval approval : approvals) {
if (handleRevocationsAsExpiry) {
int refreshed = jdbcTemplate
.update(expireApprovalStatement, (ps) -> {
ps.setTimestamp(1, new Timestamp(System.currentTimeMillis()));
ps.setString(2, approval.getUserId());
ps.setString(3, approval.getClientId());
ps.setString(4, approval.getScope());
});
if (refreshed != 1) {
success = false;
}
} else {
int refreshed = jdbcTemplate
.update(deleteApprovalStatment, (ps) -> {
ps.setString(1, approval.getUserId());
ps.setString(2, approval.getClientId());
ps.setString(3, approval.getScope());
});
if (refreshed != 1) {
success = false;
}
}
}
return success;
}

/**
* Purges expired approvals from database.
* @return {@code true} if removed successfully, {@code false} otherwise.
*/
public boolean purgeExpiredApprovals() {
logger.debug("Purging expired approvals from database");
try {
int deleted = jdbcTemplate.update(deleteApprovalStatment, (ps) -> {
ps.setTimestamp(1, new Timestamp(new Date().getTime()));
});
logger.debug(deleted + " expired approvals deleted");
} catch (DataAccessException ex) {
logger.error("Error purging expired approvals", ex);
return false;
}
return true;
}

@Override
public List<Approval> getApprovals(String userName, String clientId) {
logger.debug("Finding approvals for userName {} and cliendId {}", userName, clientId);
return jdbcTemplate.query(findApprovalStatement, rowMapper, userName, clientId);
}

private boolean updateApproval(final String sql, final Approval approval) {
logger.debug(String.format("refreshing approval: [%s]", approval));
int refreshed = jdbcTemplate.update(sql, (ps) -> {
ps.setTimestamp(1, new Timestamp(approval.getExpiresAt().getTime()));
ps.setString(2, (approval.getStatus() == null ? APPROVED
: approval.getStatus()).toString());
ps.setTimestamp(3, new Timestamp(approval.getLastUpdatedAt().getTime()));
ps.setString(4, approval.getUserId());
ps.setString(5, approval.getClientId());
ps.setString(6, approval.getScope());
});
return refreshed == 1;
}

private static class AuthorizationRowMapper implements RowMapper<Approval> {

@Override
public Approval mapRow(ResultSet rs, int rowNum) throws SQLException {
String userName = rs.getString(4);
String clientId = rs.getString(5);
String scope = rs.getString(6);
Date expiresAt = rs.getTimestamp(1);
String status = rs.getString(2);
Date lastUpdatedAt = rs.getTimestamp(3);

return new Approval(userName, clientId, scope, expiresAt,
ApprovalStatus.valueOf(status), lastUpdatedAt);
}
}
}
19 changes: 19 additions & 0 deletions src/main/java/org/radarcns/management/service/UserService.java
Original file line number Diff line number Diff line change
Expand Up @@ -109,6 +109,25 @@ public Optional<User> completePasswordReset(String newPassword, String key) {
});
}

/**
* Find the deactivated user and set the user's reset key to a new random value and set their
* reset date to now.
* Note: We do not use activation key for activating an account. It happens by resetting
* generated password. Resetting activation is by resetting reset-key and reset-date to now.
* @param login the login of the user
* @return an {@link Optional} which holds the user if an deactivated user was found with the
* given login, and is empty otherwise
*/
public Optional<User> requestActivationReset(String login) {
return userRepository.findOneByLogin(login)
.filter((p) -> !p.getActivated())
.map(user -> {
user.setResetKey(RandomUtil.generateResetKey());
user.setResetDate(ZonedDateTime.now());
return user;
});
}

/**
* Set a user's reset key to a new random value and set their reset date to now.
* @param mail the email address of the user
Expand Down
Loading

0 comments on commit c5bee2f

Please sign in to comment.