Skip to content

Commit

Permalink
Change Crowd integration from SOAP to REST (#746)
Browse files Browse the repository at this point in the history
Co-authored-by: zxBCN Valeriu_Tuguran,Constantin (IT EDP) EXTERNAL <[email protected]>
  • Loading branch information
hrcornejo and zxBCN Valeriu_Tuguran,Constantin (IT EDP) EXTERNAL authored Oct 4, 2023
1 parent 8a2fffd commit c0952ae
Show file tree
Hide file tree
Showing 27 changed files with 639 additions and 1,209 deletions.
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,9 @@

## Unreleased

### Changed
- Change Crowd integration from SOAP to REST ([#740](https://github.com/opendevstack/ods-provisioning-app/issues/740))

## [4.1] - 2022-11-17

### Added
Expand All @@ -12,7 +15,6 @@
- API DELETE*: wrong jenkins run job (lastExecutionJobs) returned ([#710](https://github.com/opendevstack/ods-provisioning-app/issues/710))
- Missing bitbucket repository description on repository creation event ([#713](https://github.com/opendevstack/ods-provisioning-app/issues/713))
- Fix problem assigning admin permissions to bitbucket repositories ([#700](https://github.com/opendevstack/ods-provisioning-app/pull/700))
- Fix problem assigning admin permissions to bitbucket repositories ([#700](https://github.com/opendevstack/ods-provisioning-app/pull/700))
- Fixes jcenter repository no more available. ([#737](https://github.com/opendevstack/ods-provisioning-app/pull/737))
- Fixes could not find com.atlassian.platform:platform:3.5.2 ([#738](https://github.com/opendevstack/ods-provisioning-app/pull/738))
- ODS AMI E2E quickstarter prov app fails due to no nexus equal false ([#730](https://github.com/opendevstack/ods-provisioning-app/pull/730))
Expand Down
24 changes: 9 additions & 15 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ repositories {
maven() {
url "https://packages.atlassian.com/maven-public/"
}
maven() {
url 'http://maven.imagej.net/content/repositories/public/'
}
}
}

Expand Down Expand Up @@ -135,21 +138,11 @@ dependencies {
transitive = true
}
implementation('javax.validation:validation-api:2.0.1.Final')
implementation('com.atlassian.crowd:crowd-integration-springsecurity:1000.82.0') {
exclude(group: 'commons-httpclient')
exclude(group: 'org.apache.ws.commons', module: 'XmlSchema')
// Explicitly excludes vulnerable versions
exclude(group: 'org.apache.struts', module: 'struts2-core')
exclude(group: 'org.apache.struts.xwork', module: 'xwork-core')
exclude(group: 'commons-collections', module: 'commons-collections')
exclude(group: 'commons-fileupload', module: 'commons-fileupload')
exclude(group: 'com.fasterxml.jackson.core', module: 'jackson-databind')
exclude(group: 'org.aspectj', module: 'aspectjweaver')
exclude(group: 'com.google.guava', module: 'guava')
}
implementation('com.atlassian.crowd:crowd-integration-springsecurity:5.1.3')
implementation group: 'javax.xml.bind', name: 'jaxb-api', version: '2.3.1'
implementation group: 'org.glassfish.jaxb', name: 'jaxb-runtime', version: '2.3.1'
implementation group: 'xerces', name: 'xercesImpl', version: '2.9.1'

// latest version of excluded libs: refactor this when upgrading to new 'com.atlassian.crowd:crowd-integration-springsecurity'
implementation('com.google.guava:guava:30.0-jre')
testImplementation('com.github.tomakehurst:wiremock-jre8:2.32.0')
}

Expand Down Expand Up @@ -221,7 +214,8 @@ task npmBuild(type:Exec) {
commandLine 'npm', 'run', 'build'
}

bootRun.dependsOn npmBuild
// Uncomment to compile npm front if frontend.spa.enabled=true in .properties
//bootRun.dependsOn npmBuild

configurations.all {
resolutionStrategy.eachDependency {
Expand Down
5 changes: 4 additions & 1 deletion client/package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@

package org.opendevstack.provision.adapter;

import com.atlassian.crowd.exception.ApplicationPermissionException;
import com.atlassian.crowd.exception.InvalidAuthenticationException;
import com.atlassian.crowd.exception.OperationFailedException;
import org.opendevstack.provision.adapter.exception.IdMgmtException;

/** Interface to wrap all (current) user based identity calls */
Expand Down Expand Up @@ -42,6 +45,10 @@ public interface IODSAuthnzAdapter {
/** Get the currently logged' in user's email */
public String getUserEmail();

void invalidate(String token)
throws InvalidAuthenticationException, OperationFailedException,
ApplicationPermissionException;

/**
* Invalidate the currently logged' in identity
*
Expand Down

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,177 @@
/*
* Copyright 2017-2019 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.opendevstack.provision.authentication.crowd;

import com.atlassian.crowd.exception.*;
import com.atlassian.crowd.integration.springsecurity.user.CrowdUserDetails;
import com.atlassian.crowd.model.group.ImmutableGroup;
import com.atlassian.crowd.service.client.CrowdClient;
import com.google.common.base.Preconditions;
import java.rmi.RemoteException;
import org.opendevstack.provision.adapter.IODSAuthnzAdapter;
import org.opendevstack.provision.adapter.exception.IdMgmtException;
import org.opendevstack.provision.authentication.SessionAwarePasswordHolder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Component;

/** Custom Authentication manager to integrate the password storing for authentication */
@Component
@ConditionalOnProperty(name = "provision.auth.provider", havingValue = "crowd")
public class CrowdAuthenticationAdapter implements IODSAuthnzAdapter {
private static final Logger logger = LoggerFactory.getLogger(CrowdAuthenticationAdapter.class);
private CrowdClient crowdClient;

@Autowired private SessionAwarePasswordHolder userPassword;

/**
* Constructor with secure SOAP restClient for crowd authentication
*
* @param crowdClient
*/
public CrowdAuthenticationAdapter(CrowdClient crowdClient) {
this.crowdClient = crowdClient;
}

/** @see IODSAuthnzAdapter#getUserPassword() */
public String getUserPassword() {
return userPassword.getPassword();
}

/** @see IODSAuthnzAdapter#getUserName() */
public String getUserName() {
return userPassword.getUsername();
}

/** @see IODSAuthnzAdapter#getToken() */
public String getToken() {
return userPassword.getToken();
}

/** @see IODSAuthnzAdapter#getUserEmail() () */
public String getUserEmail() {
Authentication auth = SecurityContextHolder.getContext().getAuthentication();

if (auth == null) {
return null;
}

if (!(auth.getPrincipal() instanceof CrowdUserDetails)) {
return null;
}

CrowdUserDetails userDetails = (CrowdUserDetails) auth.getPrincipal();

return userDetails.getEmail();
}

/** open for testing */
public void setUserPassword(String userPassword) {
this.userPassword.setPassword(userPassword);
}

/** open for testing */
public void setUserName(String userName) {
this.userPassword.setUsername(userName);
}

/**
* Invalidate a session based on a user#s token
*
* @param token the users token
* @throws RemoteException
* @throws InvalidAuthorizationTokenException
* @throws InvalidAuthenticationException
*/
@Override
public void invalidate(String token)
throws InvalidAuthenticationException, OperationFailedException,
ApplicationPermissionException {
Preconditions.checkNotNull(token);
this.getCrowdClient().invalidateSSOToken(token);
userPassword.clear();
}

@Override
public void invalidateIdentity()
throws OperationFailedException, ApplicationPermissionException,
InvalidAuthenticationException {
invalidate(getToken());
}

@Override
public boolean existsGroupWithName(String groupName) {
try {
crowdClient.getGroup(groupName);
return true;
} catch (Exception exception) {
if (!(exception instanceof GroupNotFoundException)) {
logger.error("GroupFind call failed with:", exception);
}
return false;
}
}

@Override
public boolean existPrincipalWithName(String userName) {
try {
crowdClient.getUser(userName);
return true;
} catch (Exception exception) {
if (!(exception instanceof UserNotFoundException)) {
logger.error("UserFind call failed with:", exception);
}
return false;
}
}

@Override
public String addGroup(String groupName) throws IdMgmtException {
try {
crowdClient.addGroup(ImmutableGroup.builder(groupName).build());
return groupName;
} catch (Exception ex) {
logger.error("Could not create group {}, error: {}", groupName, ex.getMessage(), ex);
throw new IdMgmtException(ex);
}
}

@Override
public String getAdapterApiUri() {
throw new UnsupportedOperationException("not supported in oauth2 or basic auth authentication");
}

/**
* get the internal secure restClient
*
* @return the secure restClient for crowd connect
*/
public CrowdClient getCrowdClient() {
return this.crowdClient;
}

/**
* Set the secure restClient for injection in tests
*
* @param crowdClient
*/
void setCrowdClient(CrowdClient crowdClient) {
this.crowdClient = crowdClient;
}
}
Loading

0 comments on commit c0952ae

Please sign in to comment.