Skip to content

Commit 097553b

Browse files
committed
Add factories as an extension mechanism for Auth
This allows library consumers to extend the standard java-saml message classes with custom implementations while still using the built-in Auth class to orchestrate the message flow, by providing a mechanism to plug-in custom object creation logic.
1 parent 8adc79b commit 097553b

File tree

5 files changed

+392
-9
lines changed

5 files changed

+392
-9
lines changed

core/src/main/java/com/onelogin/saml2/logout/LogoutResponse.java

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -95,8 +95,10 @@ public class LogoutResponse {
9595
* @param settings
9696
* OneLogin_Saml2_Settings
9797
* @param request
98-
* the HttpRequest object to be processed (Contains GET and POST parameters, request URL, ...).
99-
*
98+
* the HttpRequest object to be processed (Contains GET and POST
99+
* parameters, request URL, ...); may be <code>null</code> when
100+
* building an outgoing logout response
101+
*
100102
*/
101103
public LogoutResponse(Saml2Settings settings, HttpRequest request) {
102104
this.settings = settings;

toolkit/src/main/java/com/onelogin/saml2/Auth.java

Lines changed: 126 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,20 @@ public class Auth {
167167
* encrypted, by default tries to return the decrypted XML
168168
*/
169169
private String lastResponse;
170+
171+
private static final SamlOutgoingMessageFactory<AuthnRequestParams, AuthnRequest> DEFAULT_AUTHN_REQUEST_FACTORY = AuthnRequest::new;
172+
private static final SamlReceivedMessageFactory<SamlResponse> DEFAULT_SAML_RESPONSE_FACTORY = SamlResponse::new;
173+
private static final SamlOutgoingMessageFactory<LogoutRequestParams, LogoutRequest> DEFAULT_OUTGOING_LOGOUT_REQUEST_FACTORY = LogoutRequest::new;
174+
private static final SamlReceivedMessageFactory<LogoutRequest> DEFAULT_RECEIVED_LOGOUT_REQUEST_FACTORY = LogoutRequest::new;
175+
private static final SamlOutgoingMessageFactory<Void, LogoutResponse> DEFAULT_OUTGOING_LOGOUT_RESPONSE_FACTORY = (settings, nothing) -> new LogoutResponse(settings, null);
176+
private static final SamlReceivedMessageFactory<LogoutResponse> DEFAULT_RECEIVED_LOGOUT_RESPONSE_FACTORY = LogoutResponse::new;
177+
178+
private SamlOutgoingMessageFactory<AuthnRequestParams, AuthnRequest> authnRequestFactory = DEFAULT_AUTHN_REQUEST_FACTORY;
179+
private SamlReceivedMessageFactory<SamlResponse> samlResponseFactory = DEFAULT_SAML_RESPONSE_FACTORY;
180+
private SamlOutgoingMessageFactory<LogoutRequestParams, LogoutRequest> outgoingLogoutRequestFactory = DEFAULT_OUTGOING_LOGOUT_REQUEST_FACTORY;
181+
private SamlReceivedMessageFactory<LogoutRequest> receivedLogoutRequestFactory = DEFAULT_RECEIVED_LOGOUT_REQUEST_FACTORY;
182+
private SamlOutgoingMessageFactory<Void, LogoutResponse> outgoingLogoutResponseFactory = DEFAULT_OUTGOING_LOGOUT_RESPONSE_FACTORY;
183+
private SamlReceivedMessageFactory<LogoutResponse> receivedLogoutResponseFactory = DEFAULT_RECEIVED_LOGOUT_RESPONSE_FACTORY;
170184

171185
/**
172186
* Initializes the SP SAML instance.
@@ -609,7 +623,7 @@ public String login(String relayState, AuthnRequestParams authnRequestParams, Bo
609623
* @throws SettingsException
610624
*/
611625
public String login(String relayState, AuthnRequestParams authnRequestParams, Boolean stay, Map<String, String> parameters) throws IOException, SettingsException {
612-
AuthnRequest authnRequest = new AuthnRequest(settings, authnRequestParams);
626+
AuthnRequest authnRequest = authnRequestFactory.create(settings, authnRequestParams);
613627

614628
if (parameters == null) {
615629
parameters = new HashMap<String, String>();
@@ -785,7 +799,7 @@ public String logout(String relayState, LogoutRequestParams logoutRequestParams,
785799
parameters = new HashMap<String, String>();
786800
}
787801

788-
LogoutRequest logoutRequest = new LogoutRequest(settings, logoutRequestParams);
802+
LogoutRequest logoutRequest = outgoingLogoutRequestFactory.create(settings, logoutRequestParams);
789803
String samlLogoutRequest = logoutRequest.getEncodedLogoutRequest();
790804
parameters.put("SAMLRequest", samlLogoutRequest);
791805

@@ -1196,7 +1210,7 @@ public void processResponse(String requestId) throws Exception {
11961210
final String samlResponseParameter = httpRequest.getParameter("SAMLResponse");
11971211

11981212
if (samlResponseParameter != null) {
1199-
SamlResponse samlResponse = new SamlResponse(settings, httpRequest);
1213+
SamlResponse samlResponse = samlResponseFactory.create(settings, httpRequest);
12001214
lastResponse = samlResponse.getSAMLResponseXml();
12011215

12021216
if (samlResponse.isValid(requestId)) {
@@ -1229,7 +1243,7 @@ public void processResponse(String requestId) throws Exception {
12291243
errors.add("invalid_response");
12301244
LOGGER.error("processResponse error. invalid_response");
12311245
LOGGER.debug(" --> " + samlResponseParameter);
1232-
}
1246+
}
12331247
}
12341248
} else {
12351249
errors.add("invalid_binding");
@@ -1269,7 +1283,7 @@ public String processSLO(Boolean keepLocalSession, String requestId, Boolean sta
12691283
final String samlResponseParameter = httpRequest.getParameter("SAMLResponse");
12701284

12711285
if (samlResponseParameter != null) {
1272-
LogoutResponse logoutResponse = new LogoutResponse(settings, httpRequest);
1286+
LogoutResponse logoutResponse = receivedLogoutResponseFactory.create(settings, httpRequest);
12731287
lastResponse = logoutResponse.getLogoutResponseXml();
12741288
if (!logoutResponse.isValid(requestId)) {
12751289
errors.add("invalid_logout_response");
@@ -1299,7 +1313,7 @@ public String processSLO(Boolean keepLocalSession, String requestId, Boolean sta
12991313
}
13001314
return null;
13011315
} else if (samlRequestParameter != null) {
1302-
LogoutRequest logoutRequest = new LogoutRequest(settings, httpRequest);
1316+
LogoutRequest logoutRequest = receivedLogoutRequestFactory.create(settings, httpRequest);
13031317
lastRequest = logoutRequest.getLogoutRequestXml();
13041318
if (!logoutRequest.isValid()) {
13051319
errors.add("invalid_logout_request");
@@ -1317,7 +1331,7 @@ public String processSLO(Boolean keepLocalSession, String requestId, Boolean sta
13171331
}
13181332

13191333
String inResponseTo = logoutRequest.id;
1320-
LogoutResponse logoutResponseBuilder = new LogoutResponse(settings, httpRequest);
1334+
LogoutResponse logoutResponseBuilder = outgoingLogoutResponseFactory.create(settings, null);
13211335
logoutResponseBuilder.build(inResponseTo, Constants.STATUS_SUCCESS);
13221336
lastResponse = logoutResponseBuilder.getLogoutResponseXml();
13231337

@@ -1644,4 +1658,109 @@ public String getLastRequestXML() {
16441658
public String getLastResponseXML() {
16451659
return lastResponse;
16461660
}
1661+
1662+
/**
1663+
* Sets the factory this {@link Auth} will use to create {@link AuthnRequest}
1664+
* objects.
1665+
* <p>
1666+
* This allows consumers to provide their own extension of {@link AuthnRequest}
1667+
* possibly implementing custom features and/or XML post-processing.
1668+
*
1669+
* @param authnRequestFactory
1670+
* the factory to use to create {@link AuthnRequest} objects; if
1671+
* <code>null</code>, a default provider will be used which creates
1672+
* plain {@link AuthnRequest} instances
1673+
*/
1674+
public void setAuthnRequestFactory(
1675+
final SamlOutgoingMessageFactory<AuthnRequestParams, AuthnRequest> authnRequestFactory) {
1676+
this.authnRequestFactory = authnRequestFactory != null ? authnRequestFactory
1677+
: DEFAULT_AUTHN_REQUEST_FACTORY;
1678+
}
1679+
1680+
/**
1681+
* Sets the factory this {@link Auth} will use to create {@link SamlResponse}
1682+
* objects.
1683+
* <p>
1684+
* This allows consumers to provide their own extension of {@link SamlResponse}
1685+
* possibly implementing custom features and/or XML validation.
1686+
*
1687+
* @param samlResponseFactory
1688+
* the factory to use to create {@link SamlResponse} objects; if
1689+
* <code>null</code>, a default factory will be used which creates
1690+
* plain {@link SamlResponse} instances
1691+
*/
1692+
public void setSamlResponseFactory(final SamlReceivedMessageFactory<SamlResponse> samlResponseFactory) {
1693+
this.samlResponseFactory = samlResponseFactory != null? samlResponseFactory: DEFAULT_SAML_RESPONSE_FACTORY;
1694+
}
1695+
1696+
/**
1697+
* Sets the factory this {@link Auth} will use to create outgoing
1698+
* {@link LogoutRequest} objects.
1699+
* <p>
1700+
* This allows consumers to provide their own extension of {@link LogoutRequest}
1701+
* possibly implementing custom features and/or XML post-processing.
1702+
*
1703+
* @param outgoingLogoutRequestFactory
1704+
* the factory to use to create outgoing {@link LogoutRequest}
1705+
* objects; if <code>null</code>, a default provider will be used
1706+
* which creates plain {@link LogoutRequest} instances
1707+
*/
1708+
public void setOutgoingLogoutRequestFactory(final
1709+
SamlOutgoingMessageFactory<LogoutRequestParams, LogoutRequest> outgoingLogoutRequestFactory) {
1710+
this.outgoingLogoutRequestFactory = outgoingLogoutRequestFactory != null? outgoingLogoutRequestFactory: DEFAULT_OUTGOING_LOGOUT_REQUEST_FACTORY;
1711+
}
1712+
1713+
/**
1714+
* Sets the factory this {@link Auth} will use to create received
1715+
* {@link LogoutRequest} objects.
1716+
* <p>
1717+
* This allows consumers to provide their own extension of {@link LogoutRequest}
1718+
* possibly implementing custom features and/or XML validation.
1719+
*
1720+
* @param receivedLogoutRequestFactory
1721+
* the factory to use to create received {@link LogoutRequest}
1722+
* objects; if <code>null</code>, a default provider will be used
1723+
* which creates plain {@link LogoutRequest} instances
1724+
*/
1725+
public void setReceivedLogoutRequestFactory(
1726+
final SamlReceivedMessageFactory<LogoutRequest> receivedLogoutRequestFactory) {
1727+
this.receivedLogoutRequestFactory = receivedLogoutRequestFactory != null ? receivedLogoutRequestFactory
1728+
: DEFAULT_RECEIVED_LOGOUT_REQUEST_FACTORY;
1729+
}
1730+
1731+
/**
1732+
* Sets the factory this {@link Auth} will use to create outgoing
1733+
* {@link LogoutResponse} objects.
1734+
* <p>
1735+
* This allows consumers to provide their own extension of
1736+
* {@link LogoutResponse} possibly implementing custom features and/or XML
1737+
* post-processing.
1738+
*
1739+
* @param outgoingLogoutResponseFactory
1740+
* the factory to use to create outgoing {@link LogoutResponse}
1741+
* objects; if <code>null</code>, a default provider will be used
1742+
* which creates plain {@link LogoutResponse} instances
1743+
*/
1744+
public void setOutgoingLogoutResponseFactory(final
1745+
SamlOutgoingMessageFactory<Void, LogoutResponse> outgoingLogoutResponseFactory) {
1746+
this.outgoingLogoutResponseFactory = outgoingLogoutResponseFactory != null? outgoingLogoutResponseFactory: DEFAULT_OUTGOING_LOGOUT_RESPONSE_FACTORY;
1747+
}
1748+
1749+
/**
1750+
* Sets the factory this {@link Auth} will use to create received
1751+
* {@link LogoutResponse} objects.
1752+
* <p>
1753+
* This allows consumers to provide their own extension of
1754+
* {@link LogoutResponse} possibly implementing custom features and/or XML
1755+
* validation.
1756+
*
1757+
* @param receivedLogoutResponseFactory
1758+
* the factory to use to create received {@link LogoutResponse}
1759+
* objects; if <code>null</code>, a default provider will be used
1760+
* which creates plain {@link LogoutResponse} instances
1761+
*/
1762+
public void setReceivedLogoutResponseFactory(final
1763+
SamlReceivedMessageFactory<LogoutResponse> receivedLogoutResponseFactory) {
1764+
this.receivedLogoutResponseFactory = receivedLogoutResponseFactory != null? receivedLogoutResponseFactory: DEFAULT_RECEIVED_LOGOUT_RESPONSE_FACTORY;
1765+
}
16471766
}
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
package com.onelogin.saml2;
2+
3+
import com.onelogin.saml2.settings.Saml2Settings;
4+
5+
/**
6+
* Factory which can create an outgoing SAML message object from a
7+
* {@link Saml2Settings} instance and other input parameters.
8+
*
9+
* @param <U>
10+
* the type of input parameters required
11+
* @param <R>
12+
* the type of SAML outgoing message object created
13+
*/
14+
@FunctionalInterface
15+
public interface SamlOutgoingMessageFactory<U, R> {
16+
17+
/**
18+
* Creates an outgoing SAML message object.
19+
*
20+
* @param settings
21+
* the settings
22+
* @param params
23+
* the input parameters
24+
* @return the created received SAML message object
25+
*/
26+
R create(Saml2Settings settings, U params);
27+
}
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
package com.onelogin.saml2;
2+
3+
import com.onelogin.saml2.http.HttpRequest;
4+
import com.onelogin.saml2.settings.Saml2Settings;
5+
6+
/**
7+
* Factory which can create a received SAML message object from a
8+
* {@link Saml2Settings} instance and other input parameters.
9+
*
10+
* @param <R>
11+
* the type of received SAML message object created
12+
*/
13+
@FunctionalInterface
14+
public interface SamlReceivedMessageFactory<R> {
15+
16+
/**
17+
* Creates a received SAML message object.
18+
*
19+
* @param settings
20+
* the settings
21+
* @param httpRequest
22+
* the HTTP request
23+
* @return the created received SAML message object
24+
* @throws Exception
25+
* if the message creation fails
26+
*/
27+
R create(Saml2Settings settings, HttpRequest httpRequest) throws Exception;
28+
}

0 commit comments

Comments
 (0)