Tại thời điểm viết bài, Spring SAML có phiên bản 1.0.1.FINAL. Nó không hỗ trợ cho việc thuê nhiều bên ngoài hộp. Tôi đã tìm ra một cách khác để đạt được sự thuê nhiều bên ngoài những gợi ý của Vladimir ở trên. Nó rất đơn giản và thẳng thắn và không yêu cầu mở rộng của bất kỳ lớp học Spring SAML nào. Hơn nữa, nó sử dụng xử lý các bí danh trong xây dựng của Spring SAML trong CachingMetadataManager
.
Trong bộ điều khiển, hãy nắm bắt tên người thuê nhà từ yêu cầu và tạo đối tượng ExtendedMetadata
bằng cách sử dụng tên người thuê làm bí danh. Tiếp theo, tạo một số ExtendedMetadataDelegate
trong số ExtendedMetadata
và khởi tạo. Phân tích cú pháp các id thực thể ra khỏi nó và kiểm tra xem chúng có tồn tại trong MetadataManager
hay không. Nếu chúng không tồn tại, hãy thêm nhà cung cấp và làm mới siêu dữ liệu. Sau đó lấy id tổ chức từ MetadataManager
bằng cách sử dụng getEntityIdForAlias()
.
Đây là mã cho bộ điều khiển. Có ý kiến nội tuyến giải thích một số thông báo:
@Controller
public class SAMLController {
@Autowired
MetadataManager metadataManager;
@Autowired
ParserPool parserPool;
@RequestMapping(value = "/login.do", method = RequestMethod.GET)
public ModelAndView login(HttpServletRequest request, HttpServletResponse response, @RequestParam String tenantName)
throws MetadataProviderException, ServletException, IOException{
//load metadata url using tenant name
String tenantMetadataURL = loadTenantMetadataURL(tenantName);
//Deprecated constructor, needs to change
HTTPMetadataProvider httpMetadataProvider = new HTTPMetadataProvider(tenantMetadataURL, 15000);
httpMetadataProvider.setParserPool(parserPool);
//Create extended metadata using tenant name as the alias
ExtendedMetadata metadata = new ExtendedMetadata();
metadata.setLocal(true);
metadata.setAlias(tenantName);
//Create metadata provider and initialize it
ExtendedMetadataDelegate metadataDelegate = new ExtendedMetadataDelegate(httpMetadataProvider, metadata);
metadataDelegate.initialize();
//getEntityIdForAlias() in MetadataManager must only be called after the metadata provider
//is added and the metadata is refreshed. Otherwise, the alias will be mapped to a null
//value. The following code is a roundabout way to figure out whether the provider has already
//been added or not.
//The method parseProvider() has protected scope in MetadataManager so it was copied here
Set<String> newEntityIds = parseProvider(metadataDelegate);
Set<String> existingEntityIds = metadataManager.getIDPEntityNames();
//If one or more IDP entity ids do not exist in metadata manager, assume it's a new provider.
//If we always add a provider without this check, the initialize methods in refreshMetadata()
//ignore the provider in case of a duplicate but the duplicate still gets added to the list
//of providers because of the call to the superclass method addMetadataProvider(). Might be a bug.
if(!existingEntityIds.containsAll(newEntityIds)) {
metadataManager.addMetadataProvider(metadataDelegate);
metadataManager.refreshMetadata();
}
String entityId = metadataManager.getEntityIdForAlias(tenantName);
return new ModelAndView("redirect:/saml/login?idp=" + URLEncoder.encode(entityId, "UTF-8"));
}
private Set<String> parseProvider(MetadataProvider provider) throws MetadataProviderException {
Set<String> result = new HashSet<String>();
XMLObject object = provider.getMetadata();
if (object instanceof EntityDescriptor) {
addDescriptor(result, (EntityDescriptor) object);
} else if (object instanceof EntitiesDescriptor) {
addDescriptors(result, (EntitiesDescriptor) object);
}
return result;
}
private void addDescriptors(Set<String> result, EntitiesDescriptor descriptors) throws MetadataProviderException {
if (descriptors.getEntitiesDescriptors() != null) {
for (EntitiesDescriptor descriptor : descriptors.getEntitiesDescriptors()) {
addDescriptors(result, descriptor);
}
}
if (descriptors.getEntityDescriptors() != null) {
for (EntityDescriptor descriptor : descriptors.getEntityDescriptors()) {
addDescriptor(result, descriptor);
}
}
}
private void addDescriptor(Set<String> result, EntityDescriptor descriptor) throws MetadataProviderException {
String entityID = descriptor.getEntityID();
result.add(entityID);
}
}
Tôi tin rằng điều này trực tiếp giải quyết vấn đề của OP về cách tìm IDP cho người thuê đã cho. Nhưng điều này sẽ chỉ làm việc cho IDP với một id thực thể duy nhất.
Tôi đã tạo SAMLContextProvider của riêng mình và bỏ qua populatePeerIdentityId. Điều đó làm việc tuyệt vời. Một khi tôi đã được thực hiện tôi nhận ra rằng SAMLContextProvider chỉ được sử dụng trong SP khởi xướng SP. Chúng tôi chủ yếu sử dụng SSO do IDP khởi xướng, vì vậy tôi cũng cần phải bao gồm cả SSO.Tôi đã kết thúc kiểm tra peerEntityID của tin nhắn gửi đến đối với IDP entityID được cấu hình cho đối tượng thuê đó trong SAMLAuthenticationProvider tùy chỉnh của tôi. – MarcFasel
Tính năng này của nhà cung cấp nhận dạng bản đồ đối với nhà cung cấp dịch vụ là chìa khóa để hỗ trợ cho nhiều người thuê. Đây có phải là kế hoạch phát hành sắp tới không? – MarcFasel
Chúng ta sẽ thấy, dự án phụ thuộc vào thời gian rảnh rỗi của tôi (nó không được tài trợ bởi bất kỳ ai) và không có nhiều. Cải thiện đa hợp đồng thuê nhà là điều tôi muốn hoàn thành. –