[java-identity-provider] branch master updated: IDP-1252 - Account lockout manager needs documented means of management

Scott Cantor cantor.2 at osu.edu
Wed Jan 31 16:54:57 EST 2018


This is an automated email from the git hooks/post-receive script.

scantor pushed a commit to branch master
in repository java-identity-provider.

View the commit online:
http://git.shibboleth.net/view/?p=java-identity-provider.git;a=commit;h=4bd2251fdbf5a1dfdf0bb4454beffd94493fb20f

The following commit(s) were added to refs/heads/master by this push:
       new  4bd2251   IDP-1252 - Account lockout manager needs documented means of management
4bd2251 is described below

commit 4bd2251fdbf5a1dfdf0bb4454beffd94493fb20f
Author: Scott Cantor <cantor.2 at osu.edu>
AuthorDate: Wed Jan 31 16:54:54 2018 -0500

    IDP-1252 - Account lockout manager needs documented means of management
    
    https://issues.shibboleth.net/jira/browse/IDP-1252
---
 .../idp/authn/context/LockoutManagerContext.java   |  61 +++++
 idp-authn-impl/pom.xml                             |   5 +
 .../idp/authn/impl/DoLockoutManagerOperation.java  | 290 +++++++++++++++++++++
 .../impl/StorageBackedAccountLockoutManager.java   |  13 +-
 .../main/resources/conf/admin/general-admin.xml    |   6 +
 idp-conf/src/main/resources/conf/global.xml        |   1 -
 .../main/resources/system/conf/global-system.xml   |   9 +
 .../src/main/resources/system/conf/mvc-beans.xml   |   1 +
 .../main/resources/system/conf/webflow-config.xml  |   1 +
 .../resources/system/flows/admin/lockout-beans.xml |  43 +++
 .../resources/system/flows/admin/lockout-flow.xml  |  43 +++
 .../system/flows/authn/password-authn-beans.xml    |   9 -
 12 files changed, 471 insertions(+), 11 deletions(-)

diff --git a/idp-authn-api/src/main/java/net/shibboleth/idp/authn/context/LockoutManagerContext.java b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/context/LockoutManagerContext.java
new file mode 100644
index 0000000..e6320a8
--- /dev/null
+++ b/idp-authn-api/src/main/java/net/shibboleth/idp/authn/context/LockoutManagerContext.java
@@ -0,0 +1,61 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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 net.shibboleth.idp.authn.context;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+
+import org.opensaml.messaging.context.BaseContext;
+
+/**
+ * A context that holds information about a management operation on an
+ * {@link net.shibboleth.idp.authn.AccountLockoutManager}.
+ * 
+ * @parent {@link org.opensaml.profile.context.ProfileRequestContext}
+ * @added After the initiation of an administrative operation against a lockout manager.
+ * 
+ * @since 3.4.0
+ */
+public class LockoutManagerContext extends BaseContext {
+
+    /** Account lockout key. */
+    @Nullable private String key;
+
+    /**
+     * Get the account lockout key to check or modify.
+     * 
+     * @return account lockout key
+     */
+    @Nullable public String getKey() {
+        return key;
+    }
+
+    /**
+     * Set the account lockout key to check or modify.
+     * 
+     * @param k account lockout key
+     * 
+     * @return this context
+     */
+    @Nonnull public LockoutManagerContext setKey(@Nullable final String k) {
+        key = k;
+        
+        return this;
+    }
+    
+}
\ No newline at end of file
diff --git a/idp-authn-impl/pom.xml b/idp-authn-impl/pom.xml
index fa55087..e9dac8a 100644
--- a/idp-authn-impl/pom.xml
+++ b/idp-authn-impl/pom.xml
@@ -66,6 +66,11 @@
         </dependency>
 
         <dependency>
+          <groupId>com.github.jasminb</groupId>
+          <artifactId>jsonapi-converter</artifactId>
+        </dependency>
+
+        <dependency>
             <groupId>${spring-webflow.groupId}</groupId>
             <artifactId>spring-webflow</artifactId>
         </dependency>
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DoLockoutManagerOperation.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DoLockoutManagerOperation.java
new file mode 100644
index 0000000..f6cee98
--- /dev/null
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/DoLockoutManagerOperation.java
@@ -0,0 +1,290 @@
+/*
+ * Licensed to the University Corporation for Advanced Internet Development,
+ * Inc. (UCAID) under one or more contributor license agreements.  See the
+ * NOTICE file distributed with this work for additional information regarding
+ * copyright ownership. The UCAID licenses this file to You 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 net.shibboleth.idp.authn.impl;
+
+import java.io.IOException;
+import java.util.Collections;
+
+import javax.annotation.Nonnull;
+import javax.annotation.Nullable;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+import net.shibboleth.idp.authn.AccountLockoutManager;
+import net.shibboleth.idp.authn.context.LockoutManagerContext;
+import net.shibboleth.idp.profile.AbstractProfileAction;
+import net.shibboleth.idp.profile.context.SpringRequestContext;
+import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
+import net.shibboleth.utilities.java.support.annotation.constraint.NotEmpty;
+import net.shibboleth.utilities.java.support.component.ComponentInitializationException;
+import net.shibboleth.utilities.java.support.component.ComponentSupport;
+import net.shibboleth.utilities.java.support.logic.Constraint;
+
+import org.opensaml.profile.action.ActionSupport;
+import org.opensaml.profile.action.EventIds;
+import org.opensaml.profile.context.ProfileRequestContext;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.BeansException;
+import org.springframework.webflow.execution.RequestContext;
+
+import com.fasterxml.jackson.core.JsonFactory;
+import com.fasterxml.jackson.core.JsonGenerator;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.github.jasminb.jsonapi.models.errors.Error;
+import com.github.jasminb.jsonapi.models.errors.Errors;
+import com.google.common.base.Strings;
+
+/**
+ * Action that implements a JSON REST API for the {@link AccountLockoutManager} interface.
+ * 
+ * <p>The API supports GET, POST, and DELETE at the moment, using jsonapi.org conventions.</p>
+ * 
+ * <dl>
+ *  <dt>GET</dt>
+ *  <dd>Check for lockout.</dd>
+ *  
+ *  <dt>POST</dt>
+ *  <dd>Increment lockout.</dd>
+ *  
+ *  <dt>DELETE</dt>
+ *  <dd>Clear lockout count.</dd>
+ * </dl>
+ * 
+ * @event {@link EventIds#PROCEED_EVENT_ID}
+ * @event {@link EventIds#INVALID_PROFILE_CTX}
+ * @event {@link EventIds#IO_ERROR}
+ */
+public class DoLockoutManagerOperation extends AbstractProfileAction {
+    
+    /** Flow variable indicating ID of manager bean to access. */
+    @Nonnull @NotEmpty public static final String MANAGER_ID = "lockoutManagerId";
+
+    /** Flow variable indicating ID of account key. */
+    @Nonnull @NotEmpty public static final String KEY = "key";
+
+    /** Class logger. */
+    @Nonnull private Logger log = LoggerFactory.getLogger(DoLockoutManagerOperation.class);
+    
+    /** JSON object mapper. */
+    @NonnullAfterInit private ObjectMapper objectMapper;
+
+    /** Manager ID to operate on. */
+    @Nullable @NotEmpty private String managerId;
+
+    /** Account key to operate on. */
+    @Nullable @NotEmpty private String key;
+    
+    /** {@link AccountLockoutManager} to operate on. */
+    @Nullable private AccountLockoutManager lockoutManager;
+
+    /**
+     * Set the JSON {@link ObjectMapper} to use for serialization.
+     * 
+     * @param mapper object mapper
+     */
+    public void setObjectMapper(@Nonnull final ObjectMapper mapper) {
+        ComponentSupport.ifInitializedThrowUnmodifiabledComponentException(this);
+        
+        objectMapper = Constraint.isNotNull(mapper, "ObjectMapper cannot be null");
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected void doInitialize() throws ComponentInitializationException {
+        super.doInitialize();
+        
+        if (objectMapper == null) {
+            throw new ComponentInitializationException("ObjectMapper cannot be null");
+        }
+    }
+
+    /** {@inheritDoc} */
+    @Override
+    protected boolean doPreExecute(final ProfileRequestContext profileRequestContext) {
+        
+        if (!super.doPreExecute(profileRequestContext)) {
+            return false;
+        } else if (getHttpServletRequest() == null || getHttpServletResponse() == null) {
+            log.warn("{} No HttpServletRequest or HttpServletResponse available", getLogPrefix());
+            ActionSupport.buildEvent(profileRequestContext, EventIds.INVALID_PROFILE_CTX);
+            return false;
+        }
+        
+        try {
+            final SpringRequestContext springRequestContext =
+                    profileRequestContext.getSubcontext(SpringRequestContext.class);
+            if (springRequestContext == null) {
+                log.warn("{} Spring request context not found in profile request context", getLogPrefix());
+                sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                        "Internal Server Error", "System misconfiguration.");
+                return false;
+            }
+    
+            final RequestContext requestContext = springRequestContext.getRequestContext();
+            if (requestContext == null) {
+                log.warn("{} Web Flow request context not found in Spring request context", getLogPrefix());
+                sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR,
+                        "Internal Server Error", "System misconfiguration.");
+                return false;
+            }
+            
+            lockoutManager = getLockoutManager(requestContext);
+            if (lockoutManager == null) {
+                sendError(HttpServletResponse.SC_NOT_FOUND,
+                        "Invalid Lockout Manager", "Invalid lockout manager identifier in path.");
+                return false;
+            }
+            
+            key = (String) requestContext.getFlowScope().get(KEY);
+            if (Strings.isNullOrEmpty(key)) {
+                sendError(HttpServletResponse.SC_NOT_FOUND,
+                        "Missing Account Key", "No account key specified.");
+                return false;
+            }
+
+        } catch (final IOException e) {
+            log.error("{} I/O error issuing API response", getLogPrefix(), e);
+            ActionSupport.buildEvent(profileRequestContext, EventIds.IO_ERROR);
+            return false;
+        }
+
+        return true;
+    }
+
+    /** {@inheritDoc} */
+    @Override protected void doExecute(final ProfileRequestContext profileRequestContext) {
+
+        profileRequestContext.getSubcontext(LockoutManagerContext.class, true).setKey(key);
+        
+        try {
+            final HttpServletRequest request = getHttpServletRequest();
+            final HttpServletResponse response = getHttpServletResponse();
+            
+            response.setContentType("application/json");
+            response.setHeader("Cache-Control", "must-revalidate,no-cache,no-store");
+            
+            if ("GET".equals(request.getMethod())) {
+                try {
+                    final boolean lockout = lockoutManager.check(profileRequestContext);
+                    response.setStatus(HttpServletResponse.SC_OK);
+                    final JsonFactory jsonFactory = new JsonFactory();
+                    final JsonGenerator g = jsonFactory.createGenerator(
+                            response.getOutputStream()).useDefaultPrettyPrinter();
+                    g.setCodec(objectMapper);
+                    g.writeStartObject();
+                    g.writeObjectFieldStart("data");
+                    g.writeStringField("type", "lockout-statuses");
+                    g.writeStringField("id", managerId + '/' + key);
+                    g.writeObjectFieldStart("attributes");
+                    g.writeBooleanField("lockout", lockout);
+                    g.close();
+                } catch (final IOException e) {
+                    sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Internal Server Error", "Lockout manager error.");
+                }
+                
+            } else if ("POST".equals(request.getMethod())) {
+                try {
+                    if (lockoutManager.increment(profileRequestContext)) {
+                        response.setStatus(HttpServletResponse.SC_NO_CONTENT);
+                    } else {
+                        throw new IOException();
+                    }
+                } catch (final IOException e) {
+                    sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Internal Server Error", "Lockout manager error.");
+                }
+                
+            } else if ("DELETE".equals(request.getMethod())) {
+                try {
+                    if (lockoutManager.clear(profileRequestContext)) {
+                        response.setStatus(HttpServletResponse.SC_NO_CONTENT);
+                    } else {
+                        throw new IOException();
+                    }
+                } catch (final IOException e) {
+                    sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Internal Server Error", "Lockout manager error.");
+                }
+                
+            } else {
+                log.warn("{} Invalid method: {}", getLogPrefix(), request.getMethod());
+                sendError(HttpServletResponse.SC_METHOD_NOT_ALLOWED,
+                        "Unknown Operation", "Only GET, POST, and DELETE are supported.");
+            }
+            
+        } catch (final IOException e) {
+            log.error("{} I/O error responding to request", getLogPrefix(), e);
+            ActionSupport.buildEvent(profileRequestContext, EventIds.IO_ERROR);
+        }
+    }
+
+    /**
+     * Helper method to get the manager bean to operate on.
+     * 
+     * @param requestContext current SWF request context
+     * 
+     * @return lockout manager or null
+     */
+    @Nullable private AccountLockoutManager getLockoutManager(@Nonnull final RequestContext requestContext) {
+        
+        managerId = (String) requestContext.getFlowScope().get(MANAGER_ID);
+        if (managerId == null) {
+            log.warn("{} No {} flow variable found in request", getLogPrefix(), MANAGER_ID);
+            return null;
+        }
+        
+        try {
+            final Object bean = requestContext.getActiveFlow().getApplicationContext().getBean(managerId);
+            if (bean != null && bean instanceof AccountLockoutManager) {
+                return (AccountLockoutManager) bean;
+            }
+        } catch (final BeansException e) {
+            
+        }
+        
+        log.warn("{} No bean of the correct type found named {}", getLogPrefix(), managerId);
+        return null;
+    }
+
+    /**
+     * Output an error object.
+     * 
+     * @param status HTTP status
+     * @param title fixed error description
+     * @param detail human-readable error description
+     * 
+     * @throws IOException if unable to output the error
+     */
+    private void sendError(final int status, @Nonnull @NotEmpty final String title,
+            @Nonnull @NotEmpty final String detail) throws IOException {
+        
+        final HttpServletResponse response = getHttpServletResponse();
+        response.setContentType("application/json");
+        response.setHeader("Cache-Control", "must-revalidate,no-cache,no-store");
+        response.setStatus(status);
+        
+        final Error e = new Error();
+        final Errors errors = new Errors();
+        errors.setErrors(Collections.singletonList(e));
+        e.setStatus(Integer.toString(status));
+        e.setTitle(title);
+        e.setDetail(detail);
+        
+        objectMapper.writer().withDefaultPrettyPrinter().writeValue(response.getOutputStream(), errors);
+    }
+    
+}
\ No newline at end of file
diff --git a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/StorageBackedAccountLockoutManager.java b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/StorageBackedAccountLockoutManager.java
index ef8b63f..d6c3550 100644
--- a/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/StorageBackedAccountLockoutManager.java
+++ b/idp-authn-impl/src/main/java/net/shibboleth/idp/authn/impl/StorageBackedAccountLockoutManager.java
@@ -36,6 +36,7 @@ import com.google.common.base.Function;
 
 import net.shibboleth.idp.authn.AccountLockoutManager;
 import net.shibboleth.idp.authn.context.AuthenticationContext;
+import net.shibboleth.idp.authn.context.LockoutManagerContext;
 import net.shibboleth.idp.authn.context.UsernamePasswordContext;
 import net.shibboleth.utilities.java.support.annotation.Duration;
 import net.shibboleth.utilities.java.support.annotation.constraint.NonnullAfterInit;
@@ -405,10 +406,20 @@ public class StorageBackedAccountLockoutManager extends AbstractIdentifiableInit
 
         /** {@inheritDoc} */
         @Nullable public String apply(@Nullable final ProfileRequestContext profileRequestContext) {
-            if (profileRequestContext == null || httpRequest == null) {
+            if (profileRequestContext == null) {
                 return null;
             }
             
+            final LockoutManagerContext lockoutManagerContext =
+                    profileRequestContext.getSubcontext(LockoutManagerContext.class);
+            if (lockoutManagerContext != null) {
+                return lockoutManagerContext.getKey();
+            }
+
+            if (httpRequest == null) {
+                return null;
+            }
+
             final AuthenticationContext authenticationContext =
                     profileRequestContext.getSubcontext(AuthenticationContext.class);
             if (authenticationContext == null) {
diff --git a/idp-conf/src/main/resources/conf/admin/general-admin.xml b/idp-conf/src/main/resources/conf/admin/general-admin.xml
index 9b3b180..2a8a0e0 100644
--- a/idp-conf/src/main/resources/conf/admin/general-admin.xml
+++ b/idp-conf/src/main/resources/conf/admin/general-admin.xml
@@ -36,6 +36,12 @@
             p:loggingId="%{idp.service.logging.resolvertest:ResolverTest}"
             p:policyName="%{idp.resolvertest.accessPolicy:AccessByIPAddress}" />
 
+        <!-- REST AccountLockoutManager Access -->
+        <bean parent="shibboleth.AdminFlow"
+            c:id="http://shibboleth.net/ns/profiles/lockout-manager"
+            p:loggingId="Lockout"
+            p:policyName="AccessByIPAddress" />
+
         <!-- REST StorageService Access -->
         <bean parent="shibboleth.AdminFlow"
             c:id="http://shibboleth.net/ns/profiles/storage"
diff --git a/idp-conf/src/main/resources/conf/global.xml b/idp-conf/src/main/resources/conf/global.xml
index 60562e3..457a814 100644
--- a/idp-conf/src/main/resources/conf/global.xml
+++ b/idp-conf/src/main/resources/conf/global.xml
@@ -49,5 +49,4 @@
     </util:map>
     -->
     
-    
 </beans>
diff --git a/idp-conf/src/main/resources/system/conf/global-system.xml b/idp-conf/src/main/resources/system/conf/global-system.xml
index 10ca95c..4e6102f 100644
--- a/idp-conf/src/main/resources/system/conf/global-system.xml
+++ b/idp-conf/src/main/resources/system/conf/global-system.xml
@@ -265,6 +265,15 @@
     <bean id="shibboleth.DefaultIdentifierGenerationStrategy"
         class="net.shibboleth.utilities.java.support.security.SecureRandomIdentifierGenerationStrategy" />
 
+    <bean id="shibboleth.StorageBackedAccountLockoutManager" abstract="true"
+            class="net.shibboleth.idp.authn.impl.StorageBackedAccountLockoutManager"
+            p:storageService-ref="shibboleth.StorageService">
+        <property name="lockoutKeyStrategy">
+            <bean class="net.shibboleth.idp.authn.impl.StorageBackedAccountLockoutManager.UsernameIPLockoutKeyStrategy"
+                p:httpServletRequest-ref="shibboleth.HttpServletRequest" />
+        </property>
+    </bean>
+
     <!-- Parent beans for Signature/Encryption/TLS Configuration objects. -->
         
     <bean id="shibboleth.BasicSignatureValidationConfiguration" abstract="true"
diff --git a/idp-conf/src/main/resources/system/conf/mvc-beans.xml b/idp-conf/src/main/resources/system/conf/mvc-beans.xml
index de9468d..c08fb03 100644
--- a/idp-conf/src/main/resources/system/conf/mvc-beans.xml
+++ b/idp-conf/src/main/resources/system/conf/mvc-beans.xml
@@ -18,6 +18,7 @@
         <property name="sourceList">
             <list>
                 <value>admin/metrics</value>
+                <value>admin/lockout</value>
                 <value>admin/storage</value>
             </list>
         </property>
diff --git a/idp-conf/src/main/resources/system/conf/webflow-config.xml b/idp-conf/src/main/resources/system/conf/webflow-config.xml
index 38a7ac5..46d99b8 100644
--- a/idp-conf/src/main/resources/system/conf/webflow-config.xml
+++ b/idp-conf/src/main/resources/system/conf/webflow-config.xml
@@ -26,6 +26,7 @@
                 <entry key="admin/resolvertest" value="../system/flows/admin/resolvertest-flow.xml" />
                 <entry key="admin/reload-service" value="../system/flows/admin/reload-service-flow.xml" />
                 <entry key="admin/reload-metadata" value="../system/flows/admin/reload-metadata-flow.xml" />
+                <entry key="admin/lockout" value="../system/flows/admin/lockout-flow.xml" />
                 <entry key="admin/metrics" value="../system/flows/admin/metrics-flow.xml" />
                 <entry key="admin/storage" value="../system/flows/admin/storage-flow.xml" />
                 
diff --git a/idp-conf/src/main/resources/system/flows/admin/lockout-beans.xml b/idp-conf/src/main/resources/system/flows/admin/lockout-beans.xml
new file mode 100644
index 0000000..e7ea006
--- /dev/null
+++ b/idp-conf/src/main/resources/system/flows/admin/lockout-beans.xml
@@ -0,0 +1,43 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<beans
+    xmlns="http://www.springframework.org/schema/beans"
+    xmlns:c="http://www.springframework.org/schema/c"
+    xmlns:context="http://www.springframework.org/schema/context"
+    xmlns:p="http://www.springframework.org/schema/p"
+    xmlns:util="http://www.springframework.org/schema/util"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
+                           http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
+                           http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"
+    default-init-method="initialize"
+    default-destroy-method="destroy">
+
+    <bean class="org.springframework.context.support.PropertySourcesPlaceholderConfigurer"
+        p:placeholderPrefix="%{" p:placeholderSuffix="}" />
+
+    <import resource="admin-abstract-beans.xml" />
+
+    <!-- Profile ID for flow. -->    
+    <bean id="shibboleth.AdminProfileId" class="java.lang.String" c:_0="http://shibboleth.net/ns/profiles/lockout-manager" />
+    
+    <!-- Default operation/resource suppliers for access checks. -->
+
+    <bean id="shibboleth.AdminOperationLookupStrategy" parent="shibboleth.ContextFunctions.Expression"
+        c:outputType="#{T(java.lang.String)}"
+        c:expression="#custom.getMethod()"
+        p:customObject-ref="shibboleth.HttpServletRequest" />
+        
+    <bean id="shibboleth.AdminResourceLookupStrategy" parent="shibboleth.ContextFunctions.Expression"
+        c:outputType="#{T(java.lang.String)}"
+        c:expression="#input.getSubcontext(T(net.shibboleth.idp.profile.context.SpringRequestContext)).getRequestContext().getFlowScope().get('context')" />
+    
+    <!--  Work beans. -->
+    
+    <bean id="DoLockoutManagerOperation" class="net.shibboleth.idp.authn.impl.DoLockoutManagerOperation" scope="prototype"
+        p:httpServletRequest-ref="shibboleth.HttpServletRequest"
+        p:httpServletResponse-ref="shibboleth.HttpServletResponse"
+        p:objectMapper-ref="shibboleth.JSONObjectMapper" />
+        
+    <bean id="RecordResponseComplete" class="net.shibboleth.idp.profile.impl.RecordResponseComplete" scope="prototype" />
+        
+</beans>
diff --git a/idp-conf/src/main/resources/system/flows/admin/lockout-flow.xml b/idp-conf/src/main/resources/system/flows/admin/lockout-flow.xml
new file mode 100644
index 0000000..1a3fa33
--- /dev/null
+++ b/idp-conf/src/main/resources/system/flows/admin/lockout-flow.xml
@@ -0,0 +1,43 @@
+<flow xmlns="http://www.springframework.org/schema/webflow"
+    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
+    xsi:schemaLocation="http://www.springframework.org/schema/webflow http://www.springframework.org/schema/webflow/spring-webflow.xsd"
+    parent="admin.abstract">
+
+    <on-start>
+        <!-- Extract PATH_INFO containing lockout manager and key. -->
+        <evaluate expression="flowRequestContext.getActiveFlow().getId()" result="flowScope.flowId" />
+        <evaluate expression="externalContext.getNativeRequest().getPathInfo().length() gt flowId.length() + 2 ? externalContext.getNativeRequest().getPathInfo().substring(flowId.length() + 2) : ''" result="flowScope.pathInfo" />
+        <evaluate expression="pathInfo.split('/')" result="flowScope.pathInfoArray" />
+        <evaluate expression="pathInfoArray.length gt 0 ? T(net.shibboleth.utilities.java.support.net.URISupport).doURLDecode(pathInfoArray[0]) : null" result="flowScope.lockoutManagerId" />
+        <evaluate expression="pathInfoArray.length gt 1 ? T(net.shibboleth.utilities.java.support.net.URISupport).doURLDecode(pathInfoArray[1]) : null" result="flowScope.key" />
+    </on-start>
+
+    <!-- Start action. -->
+        
+    <action-state id="InitializeProfileRequestContext">
+        <evaluate expression="InitializeProfileRequestContext" />
+        <evaluate expression="'proceed'" />
+        
+        <!-- Branch to determine if authentication is required. -->
+        <transition on="proceed" to="DoAdminPreamble" />
+    </action-state>
+
+    <!-- Resume actual flow processing. -->
+
+    <action-state id="DoProfileWork">
+        <evaluate expression="CheckAccess" />
+        <evaluate expression="WriteAuditLog" />
+        <evaluate expression="DoLockoutManagerOperation" />
+        <evaluate expression="RecordResponseComplete" />
+        <evaluate expression="'proceed'" />
+        
+        <transition on="proceed" to="end" />
+    </action-state>
+    
+    <!-- Terminus -->
+
+    <end-state id="end" />
+    
+    <bean-import resource="lockout-beans.xml" />
+
+</flow>
diff --git a/idp-conf/src/main/resources/system/flows/authn/password-authn-beans.xml b/idp-conf/src/main/resources/system/flows/authn/password-authn-beans.xml
index 75957af..183ef27 100644
--- a/idp-conf/src/main/resources/system/flows/authn/password-authn-beans.xml
+++ b/idp-conf/src/main/resources/system/flows/authn/password-authn-beans.xml
@@ -18,15 +18,6 @@
     <bean class="net.shibboleth.ext.spring.config.IdentifiableBeanPostProcessor" />
     <bean class="net.shibboleth.idp.profile.impl.ProfileActionBeanPostProcessor" />
 
-    <bean id="shibboleth.StorageBackedAccountLockoutManager" abstract="true"
-            class="net.shibboleth.idp.authn.impl.StorageBackedAccountLockoutManager"
-            p:storageService-ref="shibboleth.StorageService">
-        <property name="lockoutKeyStrategy">
-            <bean class="net.shibboleth.idp.authn.impl.StorageBackedAccountLockoutManager.UsernameIPLockoutKeyStrategy"
-                p:httpServletRequest-ref="shibboleth.HttpServletRequest" />
-        </property>
-    </bean>
-
     <import resource="../../../conf/authn/password-authn-config.xml" />
 
     <bean id="ExtractUsernamePasswordFromBasicAuth"

-- 
To stop receiving notification emails like this one, please contact
the administrator of this repository.


More information about the commits mailing list