Skip to content

Commit

Permalink
Merge pull request #263 from reportportal/rc/5.8.1
Browse files Browse the repository at this point in the history
Release 5.8.1
  • Loading branch information
IvanKustau authored Jul 10, 2023
2 parents b7ad932 + 09d5ed1 commit 0706e3e
Show file tree
Hide file tree
Showing 9 changed files with 174 additions and 168 deletions.
6 changes: 3 additions & 3 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,9 +11,9 @@ on:

env:
GH_USER_NAME: github.actor
SCRIPTS_VERSION: 5.7.0
BOM_VERSION: 5.7.5
RELEASE_VERSION: 5.8.0
SCRIPTS_VERSION: 5.8.0
BOM_VERSION: 5.7.6
RELEASE_VERSION: 5.8.1

jobs:
release:
Expand Down
8 changes: 4 additions & 4 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
FROM alpine:latest
LABEL version=5.8.0 description="Unified Authorization Trap for all ReportPortal's Services" maintainer="Andrei Varabyeu <andrei_varabyeu@epam.com>, Hleb Kanonik <hleb_kanonik@epam.com>"
FROM amazoncorretto:11.0.17
LABEL version=5.8.1 description="Unified Authorization Trap for all ReportPortal's Services" maintainer="Andrei Varabyeu <andrei_varabyeu@epam.com>, Hleb Kanonik <hleb_kanonik@epam.com>"
ARG GH_TOKEN
RUN echo 'exec java ${JAVA_OPTS} -jar service-authorization-5.8.0-exec.jar' > /start.sh && chmod +x /start.sh && \
wget --header="Authorization: Bearer ${GH_TOKEN}" -q https://maven.pkg.github.com/reportportal/service-authorization/com/epam/reportportal/service-authorization/5.8.0/service-authorization-5.8.0-exec.jar
RUN echo 'exec java ${JAVA_OPTS} -jar service-authorization-5.8.1-exec.jar' > /start.sh && chmod +x /start.sh && \
wget --header="Authorization: Bearer ${GH_TOKEN}" -q https://maven.pkg.github.com/reportportal/service-authorization/com/epam/reportportal/service-authorization/5.8.1/service-authorization-5.8.1-exec.jar
ENV JAVA_OPTS="-Xmx512m -XX:+UseG1GC -XX:InitiatingHeapOccupancyPercent=70 -Djava.security.egd=file:/dev/./urandom"
VOLUME ["/tmp"]
EXPOSE 8080
Expand Down
2 changes: 1 addition & 1 deletion build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -53,7 +53,7 @@ dependencies {
compile 'com.epam.reportportal:commons-rules'
compile 'com.epam.reportportal:commons-model'
} else {
compile 'com.github.reportportal:commons-dao:fb1d7835'
compile 'com.github.reportportal:commons-dao:d6966878ef'
compile 'com.github.reportportal:commons-rules:331c402'
compile 'com.github.reportportal:commons-model:d61b714'
}
Expand Down
2 changes: 1 addition & 1 deletion project-properties.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ project.ext {
publishRepo = "https://maven.pkg.github.com/reportportal/service-authorization"
dependencyRepos = ["commons-dao", "commons-rules", "commons-model", "commons-bom"]
releaseMode = project.hasProperty("releaseMode")
scriptsUrl = commonScriptsUrl + (releaseMode ? getProperty('scripts.version') : 'EPMRPP-81358-fix-vulnerabilities')
scriptsUrl = commonScriptsUrl + (releaseMode ? getProperty('scripts.version') : 'master')
isDebugMode = System.getProperty("DEBUG", "false") == "true"
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,12 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.epam.reportportal.auth.integration.saml;

import static com.epam.reportportal.auth.util.AuthUtils.CROP_DOMAIN;
import static com.epam.reportportal.auth.util.AuthUtils.NORMALIZE_STRING;

import com.epam.reportportal.auth.integration.AbstractUserReplicator;
import com.epam.reportportal.auth.integration.AuthIntegrationType;
import com.epam.reportportal.auth.integration.parameter.SamlParameter;
Expand All @@ -33,133 +37,142 @@
import com.epam.ta.reportportal.exception.ReportPortalException;
import com.epam.ta.reportportal.util.PersonalProjectService;
import com.epam.ta.reportportal.ws.model.ErrorType;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.epam.reportportal.auth.util.AuthUtils.CROP_DOMAIN;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;

/**
* Replicates user from SAML response into database if it is not exist
* Replicates user from SAML response into database if it is not exist.
*
* @author Yevgeniy Svalukhin
*/
@Component
@Transactional
public class SamlUserReplicator extends AbstractUserReplicator {

private IntegrationTypeRepository integrationTypeRepository;
private IntegrationRepository integrationRepository;

@Autowired
public SamlUserReplicator(UserRepository userRepository, ProjectRepository projectRepository,
PersonalProjectService personalProjectService, UserBinaryDataService userBinaryDataService,
IntegrationTypeRepository integrationTypeRepository, IntegrationRepository integrationRepository,
ContentTypeResolver contentTypeResolver) {
super(userRepository, projectRepository, personalProjectService, userBinaryDataService, contentTypeResolver);
this.integrationTypeRepository = integrationTypeRepository;
this.integrationRepository = integrationRepository;
}

public User replicateUser(ReportPortalSamlAuthentication samlAuthentication) {
String userName = CROP_DOMAIN.apply(samlAuthentication.getPrincipal());
Optional<User> userOptional = userRepository.findByLogin(userName);

if (userOptional.isPresent()) {
return userOptional.get();
}

IntegrationType samlIntegrationType = integrationTypeRepository.findByName(AuthIntegrationType.SAML.getName())
.orElseThrow(() -> new ReportPortalException(ErrorType.AUTH_INTEGRATION_NOT_FOUND, AuthIntegrationType.SAML.getName()));

List<Integration> providers = integrationRepository.findAllGlobalByType(samlIntegrationType);

Optional<Integration> samlProvider = providers.stream().filter(provider -> {
Optional<String> idpUrlOptional = SamlParameter.IDP_URL.getParameter(provider);
return idpUrlOptional.isPresent() && idpUrlOptional.get().equalsIgnoreCase(samlAuthentication.getIssuer());
}).findFirst();

User user = new User();
user.setLogin(userName);

List<Attribute> details = samlAuthentication.getDetails();

if (samlProvider.isPresent()) {
populateUserDetailsIfSettingsArePresent(user, samlProvider.get(), details);
} else {
populateUserDetails(user, details);
}

user.setUserType(UserType.SAML);
user.setRole(UserRole.USER);
user.setExpired(false);

Project project = generatePersonalProject(user);
//TODO BUG IF PROJECT HAS NO USERS BECAUSE OF iterator().next() on empty collection
user.getProjects().add(project.getUsers().iterator().next());

user.setMetadata(defaultMetaData());

userRepository.save(user);

return user;
}

private void populateUserDetails(User user, List<Attribute> details) {
String email = findAttributeValue(details, UserAttribute.EMAIL.toString(), String.class);
checkEmail(email);
user.setEmail(email);

String firstName = findAttributeValue(details, UserAttribute.FIRST_NAME.toString(), String.class);
String lastName = findAttributeValue(details, UserAttribute.LAST_NAME.toString(), String.class);
user.setFullName(String.join(" ", firstName, lastName));
}

private void populateUserDetailsIfSettingsArePresent(User user, Integration integration, List<Attribute> details) {
String email = findAttributeValue(details, SamlParameter.EMAIL_ATTRIBUTE.getParameter(integration).orElse(null), String.class);
checkEmail(email);
user.setEmail(email);

Optional<String> idpFullNameOptional = SamlParameter.FULL_NAME_ATTRIBUTE.getParameter(integration);

if (!idpFullNameOptional.isPresent()) {
String firstName = findAttributeValue(details,
SamlParameter.FIRST_NAME_ATTRIBUTE.getParameter(integration).orElse(null),
String.class
);
String lastName = findAttributeValue(details,
SamlParameter.LAST_NAME_ATTRIBUTE.getParameter(integration).orElse(null),
String.class
);
user.setFullName(String.join(" ", firstName, lastName));
} else {
String fullName = findAttributeValue(details, idpFullNameOptional.get(), String.class);
user.setFullName(fullName);
}
}

private <T> T findAttributeValue(List<Attribute> attributes, String lookingFor, Class<T> castTo) {
if (Objects.isNull(lookingFor) || CollectionUtils.isEmpty(attributes)) {
return null;
}

Optional<Attribute> attribute = attributes.stream().filter(it -> it.getName().equalsIgnoreCase(lookingFor)).findFirst();

if (attribute.isPresent()) {
List<Object> values = attribute.get().getValues();
if (!CollectionUtils.isEmpty(values)) {
List<T> resultList = values.stream().filter(castTo::isInstance).map(castTo::cast).collect(Collectors.toList());
if (!resultList.isEmpty()) {
return resultList.get(0);
}
}
}
return null;
}
private final IntegrationTypeRepository integrationTypeRepository;
private final IntegrationRepository integrationRepository;

@Autowired
public SamlUserReplicator(UserRepository userRepository, ProjectRepository projectRepository,
PersonalProjectService personalProjectService, UserBinaryDataService userBinaryDataService,
IntegrationTypeRepository integrationTypeRepository,
IntegrationRepository integrationRepository, ContentTypeResolver contentTypeResolver) {
super(userRepository, projectRepository, personalProjectService, userBinaryDataService,
contentTypeResolver
);
this.integrationTypeRepository = integrationTypeRepository;
this.integrationRepository = integrationRepository;
}

public User replicateUser(ReportPortalSamlAuthentication samlAuthentication) {
String userName = CROP_DOMAIN.apply(samlAuthentication.getPrincipal());
Optional<User> userOptional = userRepository.findByLogin(userName);

if (userOptional.isPresent()) {
return userOptional.get();
}

IntegrationType samlIntegrationType =
integrationTypeRepository.findByName(AuthIntegrationType.SAML.getName()).orElseThrow(
() -> new ReportPortalException(ErrorType.AUTH_INTEGRATION_NOT_FOUND,
AuthIntegrationType.SAML.getName()
));

List<Integration> providers = integrationRepository.findAllGlobalByType(samlIntegrationType);

Optional<Integration> samlProvider = providers.stream().filter(provider -> {
Optional<String> idpUrlOptional = SamlParameter.IDP_URL.getParameter(provider);
return idpUrlOptional.isPresent() && idpUrlOptional.get()
.equalsIgnoreCase(samlAuthentication.getIssuer());
}).findFirst();

User user = new User();
user.setLogin(userName);

List<Attribute> details = samlAuthentication.getDetails();

if (samlProvider.isPresent()) {
populateUserDetailsIfSettingsArePresent(user, samlProvider.get(), details);
} else {
populateUserDetails(user, details);
}

user.setUserType(UserType.SAML);
user.setRole(UserRole.USER);
user.setExpired(false);

Project project = generatePersonalProject(user);
//TODO BUG IF PROJECT HAS NO USERS BECAUSE OF iterator().next() on empty collection
user.getProjects().add(project.getUsers().iterator().next());

user.setMetadata(defaultMetaData());

userRepository.save(user);

return user;
}

private void populateUserDetails(User user, List<Attribute> details) {
String email = NORMALIZE_STRING.apply(
findAttributeValue(details, UserAttribute.EMAIL.toString(), String.class));
checkEmail(email);
user.setEmail(email);

String firstName =
findAttributeValue(details, UserAttribute.FIRST_NAME.toString(), String.class);
String lastName = findAttributeValue(details, UserAttribute.LAST_NAME.toString(), String.class);
user.setFullName(String.join(" ", firstName, lastName));
}

private void populateUserDetailsIfSettingsArePresent(User user, Integration integration,
List<Attribute> details) {
String email = NORMALIZE_STRING.apply(findAttributeValue(details,
SamlParameter.EMAIL_ATTRIBUTE.getParameter(integration).orElse(null), String.class
));
checkEmail(email);
user.setEmail(email);

Optional<String> idpFullNameOptional =
SamlParameter.FULL_NAME_ATTRIBUTE.getParameter(integration);

if (!idpFullNameOptional.isPresent()) {
String firstName = findAttributeValue(details,
SamlParameter.FIRST_NAME_ATTRIBUTE.getParameter(integration).orElse(null), String.class
);
String lastName = findAttributeValue(details,
SamlParameter.LAST_NAME_ATTRIBUTE.getParameter(integration).orElse(null), String.class
);
user.setFullName(String.join(" ", firstName, lastName));
} else {
String fullName = findAttributeValue(details, idpFullNameOptional.get(), String.class);
user.setFullName(fullName);
}
}

private <T> T findAttributeValue(List<Attribute> attributes, String lookingFor, Class<T> castTo) {
if (Objects.isNull(lookingFor) || CollectionUtils.isEmpty(attributes)) {
return null;
}

Optional<Attribute> attribute =
attributes.stream().filter(it -> it.getName().equalsIgnoreCase(lookingFor)).findFirst();

if (attribute.isPresent()) {
List<Object> values = attribute.get().getValues();
if (!CollectionUtils.isEmpty(values)) {
List<T> resultList = values.stream().filter(castTo::isInstance).map(castTo::cast)
.collect(Collectors.toList());
if (!resultList.isEmpty()) {
return resultList.get(0);
}
}
}
return null;
}
}
30 changes: 16 additions & 14 deletions src/main/java/com/epam/reportportal/auth/util/AuthUtils.java
Original file line number Diff line number Diff line change
Expand Up @@ -13,18 +13,19 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package com.epam.reportportal.auth.util;

import com.epam.ta.reportportal.entity.user.UserRole;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import static com.epam.ta.reportportal.commons.EntityUtils.normalizeId;

import com.epam.ta.reportportal.entity.user.UserRole;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;

import static com.epam.ta.reportportal.commons.EntityUtils.normalizeId;
import java.util.function.UnaryOperator;
import org.apache.commons.lang3.StringUtils;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;

/**
* Authentication utils
Expand All @@ -33,13 +34,14 @@
*/
public final class AuthUtils {

private AuthUtils() {
//statics only
}

public static final Function<UserRole, List<GrantedAuthority>> AS_AUTHORITIES = userRole -> Collections.singletonList(new SimpleGrantedAuthority(
userRole.getAuthority()));

public static final Function<String, String> CROP_DOMAIN = it -> normalizeId(StringUtils.substringBefore(it, "@"));
public static final Function<UserRole, List<GrantedAuthority>> AS_AUTHORITIES =
userRole -> Collections.singletonList(new SimpleGrantedAuthority(userRole.getAuthority()));
public static final Function<String, String> CROP_DOMAIN =
it -> normalizeId(StringUtils.substringBefore(it, "@"));
public static final UnaryOperator<String> NORMALIZE_STRING =
original -> normalizeId(original.trim());

private AuthUtils() {
//statics only
}
}
14 changes: 7 additions & 7 deletions src/main/resources/application-dev.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,10 @@ rp:
auth:
saml:
base-path: http://localhost:9999
binarystore:
type: filesystem
s3:
endpoint: http://localhost:9000
accessKey:
secretKey:
path: ${java.io.tmpdir}${file.separator}reportportal${file.separator}datastore

datastore:
type: filesystem
path: ${java.io.tmpdir}${file.separator}reportportal${file.separator}datastore
endpoint: http://localhost:9000
accessKey:
secretKey:
Loading

0 comments on commit 0706e3e

Please sign in to comment.