Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: update the plugin to use Spring framework classes #261

Merged
merged 3 commits into from
Aug 29, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,11 @@

package org.jenkinsci.plugins.saml;

import org.acegisecurity.providers.AbstractAuthenticationToken;

import javax.annotation.Nonnull;
import org.springframework.security.authentication.AbstractAuthenticationToken;

/**
* @see org.acegisecurity.Authentication
* @see AbstractAuthenticationToken
*/
public final class SamlAuthenticationToken extends AbstractAuthenticationToken {

Expand Down
43 changes: 0 additions & 43 deletions src/main/java/org/jenkinsci/plugins/saml/SamlGroupAuthority.java

This file was deleted.

16 changes: 5 additions & 11 deletions src/main/java/org/jenkinsci/plugins/saml/SamlGroupDetails.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,11 @@
under the License. */
package org.jenkinsci.plugins.saml;

import java.util.HashSet;
import java.util.Set;
import hudson.model.User;
import hudson.security.GroupDetails;
import jenkins.security.LastGrantedAuthoritiesProperty;
import org.acegisecurity.GrantedAuthority;

import java.util.HashSet;
import java.util.Set;


/**
Expand Down Expand Up @@ -52,23 +50,19 @@ public String getDisplayName() {
@Override
public Set<String> getMembers() {
if (members.isEmpty()) {
for (User u : User.getAll()) {
User.getAll().forEach(u -> {
LastGrantedAuthoritiesProperty prop = u.getProperty(LastGrantedAuthoritiesProperty.class);
if (hasGroupOnAuthorities(prop)) {
members.add(u.getId());
}
}
});
}
return members;
}

private boolean hasGroupOnAuthorities(LastGrantedAuthoritiesProperty prop) {
if (prop != null) {
for (GrantedAuthority a : prop.getAuthorities()) {
if (name.equals(a.getAuthority())) {
return true;
}
}
return prop.getAuthorities2().stream().anyMatch(a -> name.equals(a.getAuthority()));
}
return false;
}
Expand Down
97 changes: 56 additions & 41 deletions src/main/java/org/jenkinsci/plugins/saml/SamlSecurityRealm.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,20 +17,18 @@

package org.jenkinsci.plugins.saml;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.annotation.Nonnull;
import javax.servlet.http.HttpSession;
import edu.umd.cs.findbugs.annotations.NonNull;
import hudson.Extension;
import hudson.Util;
import hudson.security.GroupDetails;
import hudson.security.UserMayOrMayNotExistException;
import hudson.util.FormValidation;
import hudson.model.Descriptor;
import hudson.model.User;
import hudson.security.SecurityRealm;
import hudson.tasks.Mailer.UserProperty;
import jenkins.model.Jenkins;
import jenkins.security.SecurityListener;
import org.acegisecurity.*;
import org.acegisecurity.context.SecurityContextHolder;
import org.acegisecurity.Authentication;
import org.acegisecurity.userdetails.UsernameNotFoundException;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;
Expand All @@ -39,23 +37,35 @@
import org.jenkinsci.plugins.saml.user.SamlCustomProperty;
import org.kohsuke.accmod.Restricted;
import org.kohsuke.accmod.restrictions.NoExternalUse;
import org.kohsuke.stapler.*;
import org.kohsuke.stapler.DataBoundConstructor;
import org.kohsuke.stapler.Header;
import org.kohsuke.stapler.HttpResponse;
import org.kohsuke.stapler.HttpResponses;
import org.kohsuke.stapler.QueryParameter;
import org.kohsuke.stapler.StaplerRequest;
import org.kohsuke.stapler.StaplerResponse;
import org.kohsuke.stapler.interceptor.RequirePOST;
import org.pac4j.core.redirect.RedirectAction;
import org.pac4j.core.redirect.RedirectAction.RedirectType;
import org.springframework.dao.DataAccessException;
import org.pac4j.saml.profile.SAML2Profile;

import javax.annotation.Nonnull;
import javax.servlet.http.HttpSession;
import java.io.*;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;

import static org.apache.commons.codec.binary.Base64.*;
import org.springframework.dao.DataAccessException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import hudson.Extension;
import hudson.Util;
import hudson.model.Descriptor;
import hudson.model.User;
import hudson.security.ACL;
import hudson.security.GroupDetails;
import hudson.security.SecurityRealm;
import hudson.security.UserMayOrMayNotExistException2;
import hudson.tasks.Mailer.UserProperty;
import hudson.util.FormValidation;
import jenkins.model.Jenkins;
import jenkins.security.SecurityListener;
import static org.apache.commons.codec.binary.Base64.decodeBase64;
import static org.apache.commons.codec.binary.Base64.isBase64;
import static org.opensaml.saml.common.xml.SAMLConstants.SAML2_REDIRECT_BINDING_URI;

/**
Expand Down Expand Up @@ -215,15 +225,11 @@ public boolean allowsSignup() {
@Override
public SecurityComponents createSecurityComponents() {
LOG.finer("createSecurityComponents");
return new SecurityComponents(new AuthenticationManager() {

public Authentication authenticate(Authentication authentication) throws AuthenticationException {
if (authentication instanceof SamlAuthenticationToken) {
return authentication;
}
throw new BadCredentialsException("Unexpected authentication type: " + authentication);
return new SecurityComponents(authentication -> {
if (authentication instanceof SamlAuthenticationToken) {
return authentication;
}

throw new BadCredentialsException("Unexpected authentication type: " + authentication);
}, new SamlUserDetailsService());
}

Expand Down Expand Up @@ -319,13 +325,12 @@ public HttpResponse doFinishLogin(final StaplerRequest request, final StaplerRes
List<GrantedAuthority> authorities = loadGrantedAuthorities(saml2Profile);

// create user data
SamlUserDetails userDetails = new SamlUserDetails(username, authorities.toArray(new GrantedAuthority[authorities.size()]));
SamlUserDetails userDetails = new SamlUserDetails(username, authorities);

SamlAuthenticationToken samlAuthToken = new SamlAuthenticationToken(userDetails);

// initialize security context
SecurityContextHolder.getContext().setAuthentication(samlAuthToken);
SecurityListener.fireAuthenticated(userDetails);
ACL.as2(samlAuthToken);
SecurityListener.fireAuthenticated2(userDetails);
User user = User.current();

saveUser |= modifyUserFullName(user, saml2Profile);
Expand Down Expand Up @@ -491,11 +496,11 @@ List<GrantedAuthority> loadGrantedAuthorities(SAML2Profile saml2Profile) {

// build list of authorities
List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(AUTHENTICATED_AUTHORITY);
authorities.add(AUTHENTICATED_AUTHORITY2);
int countEmptyGroups = 0;
for (String group : groups) {
if (StringUtils.isNotBlank(group)) {
authorities.add(new SamlGroupAuthority(group));
authorities.add(new SimpleGrantedAuthority(group));
} else {
countEmptyGroups++;
}
Expand Down Expand Up @@ -614,16 +619,26 @@ public void doLogout(StaplerRequest req, StaplerResponse rsp) throws IOException
LOG.log(Level.FINEST, "Here we could do the SAML Single Logout");
}

/**
* This method is overwritten due to SAML has no way to retrieve the members of a Group and this cause issues on
* some Authorization plugins. Because of that we have to implement SamlGroupDetails
*/
@SuppressWarnings("deprecation")
@Override
public GroupDetails loadGroupByGroupname(String groupname) throws UsernameNotFoundException, DataAccessException {
GroupDetails dg = new SamlGroupDetails(groupname);

if (dg.getMembers().isEmpty()) {
throw new UserMayOrMayNotExistException(groupname);
throw new UserMayOrMayNotExistException2(groupname);
}
return dg;
}

/**
* This method is overwritten due to SAML has no way to retrieve the members of a Group and this cause issues on
* some Authorization plugins. Because of that we have to implement SamlGroupDetails
*/
@SuppressWarnings("deprecation")
@Override
public GroupDetails loadGroupByGroupname(String groupname, boolean fetchMembers)
throws UsernameNotFoundException, DataAccessException {
Expand Down
18 changes: 10 additions & 8 deletions src/main/java/org/jenkinsci/plugins/saml/SamlUserDetails.java
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,14 @@

package org.jenkinsci.plugins.saml;

import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.userdetails.UserDetails;

import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import javax.annotation.Nonnull;
import java.util.Arrays;
import java.util.Collections;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;

/**
* @see UserDetails
Expand All @@ -32,15 +34,15 @@ public class SamlUserDetails implements UserDetails {
private static final long serialVersionUID = 2L;

private final String username;
private final GrantedAuthority[] authorities;
private final Collection<GrantedAuthority> authorities;

public SamlUserDetails(@Nonnull String username, GrantedAuthority[] authorities) {
public SamlUserDetails(@Nonnull String username, Collection<GrantedAuthority> authorities) {
this.username = username;
this.authorities = Arrays.copyOf(authorities, authorities.length);
this.authorities = Collections.unmodifiableCollection(authorities);
}

public GrantedAuthority[] getAuthorities() {
return Arrays.copyOf(authorities, authorities.length);
public Collection<GrantedAuthority> getAuthorities() {
return authorities;
}

public String getPassword() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,19 +17,19 @@

package org.jenkinsci.plugins.saml;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.annotation.Nonnull;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetailsService;
import hudson.model.User;
import hudson.security.SecurityRealm;
import hudson.security.UserMayOrMayNotExistException2;
import jenkins.model.Jenkins;
import jenkins.security.LastGrantedAuthoritiesProperty;
import org.acegisecurity.Authentication;
import org.acegisecurity.GrantedAuthority;
import org.acegisecurity.userdetails.UserDetailsService;

import javax.annotation.Nonnull;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

/**
* This service is responsible for restoring UserDetails object by userId
Expand All @@ -41,7 +41,7 @@ public class SamlUserDetailsService implements UserDetailsService {
public SamlUserDetails loadUserByUsername(@Nonnull String username) {

// try to obtain user details from current authentication details
Authentication auth = Jenkins.getAuthentication();
Authentication auth = Jenkins.getAuthentication2();
if (username.compareTo(auth.getName()) == 0 && auth instanceof SamlAuthenticationToken) {
return (SamlUserDetails) auth.getDetails();
}
Expand All @@ -53,20 +53,20 @@ public SamlUserDetails loadUserByUsername(@Nonnull String username) {
throw new UserMayOrMayNotExistException2(username);
}

List<GrantedAuthority> authorities = new ArrayList<>();
authorities.add(SecurityRealm.AUTHENTICATED_AUTHORITY);
List<GrantedAuthority>authorities = new ArrayList<>();
authorities.add(SecurityRealm.AUTHENTICATED_AUTHORITY2);

if (username.compareTo(user.getId()) == 0) {
LastGrantedAuthoritiesProperty lastGranted = user.getProperty(LastGrantedAuthoritiesProperty.class);
if (lastGranted != null) {
for (GrantedAuthority a : lastGranted.getAuthorities()) {
if (a != SecurityRealm.AUTHENTICATED_AUTHORITY) {
SamlGroupAuthority ga = new SamlGroupAuthority(a.getAuthority());
for (GrantedAuthority a : lastGranted.getAuthorities2()) {
if (a != SecurityRealm.AUTHENTICATED_AUTHORITY2) {
SimpleGrantedAuthority ga = new SimpleGrantedAuthority(a.getAuthority());
authorities.add(ga);
}
}
}
}
return new SamlUserDetails(user.getId(), authorities.toArray(new GrantedAuthority[0]));
return new SamlUserDetails(user.getId(), authorities);
}
}
Loading