Skip to content

Commit

Permalink
Add SSO login using access token
Browse files Browse the repository at this point in the history
  • Loading branch information
jenshp committed Jun 4, 2024
1 parent 1c69844 commit e34f26a
Show file tree
Hide file tree
Showing 7 changed files with 46 additions and 1 deletion.
2 changes: 1 addition & 1 deletion framework/service/org/moqui/impl/UserServices.xml
Original file line number Diff line number Diff line change
Expand Up @@ -96,7 +96,7 @@ along with this software (see the LICENSE.md file). If not, see
</else-if></if>
</actions>
</service>
<service verb="update" noun="UserAccount">
<service verb="update" noun="UserAccount" authenticate="anonymous-all" allow-remote="false">
<in-parameters>
<parameter name="userId" required="true"/>
<auto-parameters entity-name="moqui.security.UserAccount" include="nonpk">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1642,6 +1642,7 @@ class ExecutionContextFactoryImpl implements ExecutionContextFactory {
if (overrideNode.hasChild("user-facade")) {
MNode ufBaseNode = baseNode.first("user-facade")
MNode ufOverrideNode = overrideNode.first("user-facade")
ufBaseNode.attributes.putAll(ufOverrideNode.attributes)
ufBaseNode.mergeSingleChild(ufOverrideNode, "password")
ufBaseNode.mergeSingleChild(ufOverrideNode, "login-key")
ufBaseNode.mergeSingleChild(ufOverrideNode, "login")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ import org.moqui.impl.context.runner.JavaxScriptRunner
import org.moqui.impl.context.runner.XmlActionsScriptRunner
import org.moqui.impl.entity.EntityValueBase
import org.moqui.jcache.MCache
import org.moqui.security.SingleSignOnTokenLoginHandler
import org.moqui.util.ContextBinding
import org.moqui.util.ContextStack
import org.moqui.util.MNode
Expand Down Expand Up @@ -59,6 +60,7 @@ class ResourceFacadeImpl implements ResourceFacade {

final FtlTemplateRenderer ftlTemplateRenderer
final XmlActionsScriptRunner xmlActionsScriptRunner
protected final ToolFactory<SingleSignOnTokenLoginHandler> ssoTokenHandlerFactory = null

// the groovy Script object is not thread safe, so have one per thread per expression; can be reused as thread is reused
protected final ThreadLocal<Map<String, Script>> threadScriptByExpression = new ThreadLocal<>()
Expand Down Expand Up @@ -164,6 +166,16 @@ class ResourceFacadeImpl implements ResourceFacade {
logger.error("Error getting JCR Repository ${repositoryNode.attribute("name")}: ${e.toString()}")
}
}

MNode userFacadeNode = ecfi.confXmlRoot.first("user-facade")
if (userFacadeNode.attribute("sso-access-token-handler-factory")) {
ssoTokenHandlerFactory = ecfi.getToolFactory(userFacadeNode.attribute("sso-access-token-handler-factory"))
if (ssoTokenHandlerFactory != null) {
logger.info("Using sso-access-token-handler-factory ${userFacadeNode.attribute("sso-access-token-handler-factory")} (${ssoTokenHandlerFactory.class.name})")
} else {
logger.warn("Could not find sso-access-token-handler-factory with name ${userFacadeNode.attribute("sso-access-token-handler-factory")}")
}
}
}

void destroyAllInThread() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ import groovy.transform.CompileStatic
import org.apache.shiro.authc.AuthenticationToken
import org.apache.shiro.authc.ExpiredCredentialsException
import org.moqui.context.PasswordChangeRequiredException
import org.moqui.security.SingleSignOnTokenLoginHandler

import javax.websocket.server.HandshakeRequest
import java.sql.Timestamp
Expand Down Expand Up @@ -172,6 +173,14 @@ class UserFacadeImpl implements UserFacade {
if (loginKey != null && !loginKey.isEmpty() && !"null".equals(loginKey) && !"undefined".equals(loginKey))
this.loginUserKey(loginKey)
}
if (currentInfo.username == null && request.getHeader("sso_access_token")) {
String ssoAccessToken = request.getHeader("sso_access_token").trim()
String ssoAuthFlowId = request.getHeader("sso_auth_flow")
if (ssoAuthFlowId)
ssoAuthFlowId = ssoAuthFlowId.trim()
if (!ssoAccessToken.isEmpty() && !"null".equals(ssoAccessToken) && !"undefined".equals(ssoAccessToken))
this.loginSsoToken(ssoAccessToken, ssoAuthFlowId)
}
if (currentInfo.username == null && secureParameters.authUsername) {
// try the Moqui-specific parameters for instant login
// if we have credentials coming in anywhere other than URL parameters, try logging in
Expand Down Expand Up @@ -802,6 +811,15 @@ class UserFacadeImpl implements UserFacade {
return loginKey
}

@Override boolean loginSsoToken(String ssoAccessToken, String ssoAuthFlowId) {
if (eci.resourceFacade.ssoTokenHandlerFactory == null) {
eci.logger.error("No SingleSignOnTokenLoginHandler ToolFactory configured, cannot handle SsoToken login")
return false
}
final SingleSignOnTokenLoginHandler ssoTokenLoginHandler = eci.resourceFacade.ssoTokenHandlerFactory.getInstance()
return ssoTokenLoginHandler.handleSsoLoginToken(eci, ssoAccessToken, ssoAuthFlowId)
}

@Override boolean loginAnonymousIfNoUser() {
if (currentInfo.username == null && !currentInfo.loggedInAnonymous) {
currentInfo.loggedInAnonymous = true
Expand Down
6 changes: 6 additions & 0 deletions framework/src/main/java/org/moqui/context/UserFacade.java
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,12 @@ public interface UserFacade {
String getLoginKey();
String getLoginKey(float expireHours);

/** Authenticate a user and make active using a SSO access token
* @param ssoAccessToken the accessToken provided by the SSO server
* @param ssoAuthFlowId the (optional) authFlowId for identifying the SSO server
*/
boolean loginSsoToken(String ssoAccessToken, String ssoAuthFlowId);

/** If no user is logged in consider an anonymous user logged in. For internal purposes to run things that require authentication. */
boolean loginAnonymousIfNoUser();

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package org.moqui.security;

import org.moqui.context.ExecutionContext;

public interface SingleSignOnTokenLoginHandler {
public boolean handleSsoLoginToken(ExecutionContext ec, String ssoAccessToken, String ssoAuthFlowId);
}
1 change: 1 addition & 0 deletions framework/xsd/moqui-conf-3.xsd
Original file line number Diff line number Diff line change
Expand Up @@ -335,6 +335,7 @@ along with this software (see the LICENSE.md file). If not, see
<xs:element minOccurs="0" ref="login-key"/>
<xs:element minOccurs="0" ref="login"/>
</xs:sequence>
<xs:attribute name="sso-access-token-handler-factory" type="xs:string"/>
</xs:complexType>
</xs:element>
<xs:element name="password">
Expand Down

0 comments on commit e34f26a

Please sign in to comment.