You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@shiro.apache.org by bd...@apache.org on 2016/11/08 14:50:06 UTC

shiro git commit: Initial commit for openid4j support

Repository: shiro
Updated Branches:
  refs/heads/openid4j [created] aef52690d


Initial commit for openid4j support

This reverts commit 3a23929a8d3d2f13ebe3365ca66f94d51b5bdbe6.


Project: http://git-wip-us.apache.org/repos/asf/shiro/repo
Commit: http://git-wip-us.apache.org/repos/asf/shiro/commit/aef52690
Tree: http://git-wip-us.apache.org/repos/asf/shiro/tree/aef52690
Diff: http://git-wip-us.apache.org/repos/asf/shiro/diff/aef52690

Branch: refs/heads/openid4j
Commit: aef52690df6105cb260207fb622094fdc8c161ca
Parents: e8ba5cb
Author: Brian Demers <bd...@apache.org>
Authored: Tue Nov 8 09:48:39 2016 -0500
Committer: Brian Demers <bd...@apache.org>
Committed: Tue Nov 8 09:49:44 2016 -0500

----------------------------------------------------------------------
 pom.xml                                         |  10 ++
 support/openid4j/pom.xml                        |  91 ++++++++++
 .../shiro/openid4j/ConstructedRequest.java      |  33 ++++
 .../shiro/openid4j/DefaultOpenIdService.java    | 148 +++++++++++++++++
 .../shiro/openid4j/DiscoveryException.java      |  29 ++++
 .../shiro/openid4j/DiscoveryIdResolver.java     |  27 +++
 .../shiro/openid4j/MessageExtensionFactory.java |  31 ++++
 .../apache/shiro/openid4j/OpenIdException.java  |  31 ++++
 .../apache/shiro/openid4j/OpenIdService.java    |  29 ++++
 .../openid4j/SimpleConstructedRequest.java      |  44 +++++
 .../shiro/openid4j/ax/AttributeDefinition.java  |  34 ++++
 .../shiro/openid4j/ax/AttributeProperty.java    | 118 +++++++++++++
 .../shiro/openid4j/ax/FetchRequestFactory.java  | 164 +++++++++++++++++++
 .../openid4j/ax/SimpleAttributeDefinition.java  |  74 +++++++++
 .../shiro/openid4j/realm/RelyingPartyRealm.java |  57 +++++++
 .../groovy/AttributeTypeScreenScraper.groovy    | 100 +++++++++++
 .../openid4j/ax/FetchRequestFactoryTest.groovy  |  47 ++++++
 .../src/test/resources/log4j.properties         |  37 +++++
 support/pom.xml                                 |   1 +
 19 files changed, 1105 insertions(+)
----------------------------------------------------------------------


http://git-wip-us.apache.org/repos/asf/shiro/blob/aef52690/pom.xml
----------------------------------------------------------------------
diff --git a/pom.xml b/pom.xml
index 8fe6095..be27f19 100644
--- a/pom.xml
+++ b/pom.xml
@@ -86,6 +86,7 @@
         <hsqldb.version>1.8.0.7</hsqldb.version>
         <jdk.version>1.6</jdk.version>
         <jetty.version>9.3.0.M1</jetty.version>
+        <openid4j.version>0.9.5</openid4j.version>
         <!-- Don't change this version without also changing the shiro-quartz and shiro-features
              modules' OSGi metadata: -->
         <quartz.version>1.6.1</quartz.version>
@@ -736,6 +737,15 @@
             </dependency>
 
             <dependency>
+                <groupId>org.openid4java</groupId>
+                <artifactId>openid4java-consumer</artifactId>
+                <!--artifactId>openid4java-server</artifactId-->
+                <!--artifactId>openid4java-infocard</artifactId-->
+                <!--artifactId>openid4java-xri</artifactId-->
+                <!--artifactId>openid4java</artifactId-->
+                <version>${openid4j.version}</version>
+            </dependency>
+            <dependency>
                 <!-- Used for Atlassian Crowd Realm - not required for the framework: -->
                 <groupId>com.atlassian.crowd</groupId>
                 <artifactId>crowd-integration-client</artifactId>

http://git-wip-us.apache.org/repos/asf/shiro/blob/aef52690/support/openid4j/pom.xml
----------------------------------------------------------------------
diff --git a/support/openid4j/pom.xml b/support/openid4j/pom.xml
new file mode 100644
index 0000000..44c7c01
--- /dev/null
+++ b/support/openid4j/pom.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+  ~ Licensed to the Apache Software Foundation (ASF) under one
+  ~ or more contributor license agreements.  See the NOTICE file
+  ~ distributed with this work for additional information
+  ~ regarding copyright ownership.  The ASF 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.
+  -->
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+
+    <parent>
+        <groupId>org.apache.shiro</groupId>
+        <artifactId>shiro-root</artifactId>
+        <version>2.alpha.0-SNAPSHOT</version>
+        <relativePath>../../pom.xml</relativePath>
+    </parent>
+
+    <modelVersion>4.0.0</modelVersion>
+    <artifactId>shiro-openid4j</artifactId>
+    <name>Apache Shiro :: Support :: OpenId4J</name>
+    <packaging>bundle</packaging>
+
+    <dependencies>
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-core</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.shiro</groupId>
+            <artifactId>shiro-web</artifactId>
+        </dependency>
+        <dependency>
+            <groupId>javax.servlet</groupId>
+            <artifactId>javax.servlet-api</artifactId>
+            <scope>provided</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.openid4java</groupId>
+            <artifactId>openid4java-consumer</artifactId>
+        </dependency>
+
+        <!-- Test dependencies -->
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>jcl-over-slf4j</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>org.slf4j</groupId>
+            <artifactId>slf4j-log4j12</artifactId>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>log4j</groupId>
+            <artifactId>log4j</artifactId>
+            <scope>test</scope>
+        </dependency>
+    </dependencies>
+
+    <build>
+        <plugins>
+            <plugin>
+                <groupId>org.apache.felix</groupId>
+                <artifactId>maven-bundle-plugin</artifactId>
+                <extensions>true</extensions>
+                <configuration>
+                    <instructions>
+                        <Bundle-SymbolicName>org.apache.shiro.openid4j</Bundle-SymbolicName>
+                        <Export-Package>org.apache.shiro.openid4j*;version=${project.version}</Export-Package>
+                        <Import-Package>
+                            org.apache.shiro*;version="${shiro.osgi.importRange}",
+                            *
+                        </Import-Package>
+                    </instructions>
+                </configuration>
+            </plugin>
+        </plugins>
+    </build>
+
+</project>

http://git-wip-us.apache.org/repos/asf/shiro/blob/aef52690/support/openid4j/src/main/java/org/apache/shiro/openid4j/ConstructedRequest.java
----------------------------------------------------------------------
diff --git a/support/openid4j/src/main/java/org/apache/shiro/openid4j/ConstructedRequest.java b/support/openid4j/src/main/java/org/apache/shiro/openid4j/ConstructedRequest.java
new file mode 100644
index 0000000..4f3b7f8
--- /dev/null
+++ b/support/openid4j/src/main/java/org/apache/shiro/openid4j/ConstructedRequest.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 org.apache.shiro.openid4j;
+
+import org.openid4java.discovery.DiscoveryInformation;
+import org.openid4java.message.AuthRequest;
+
+/**
+ *
+ * @since 1.2
+ */
+public interface ConstructedRequest {
+
+    DiscoveryInformation getDiscoveryInfo();
+
+    AuthRequest getAuthenticationRequest();
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/aef52690/support/openid4j/src/main/java/org/apache/shiro/openid4j/DefaultOpenIdService.java
----------------------------------------------------------------------
diff --git a/support/openid4j/src/main/java/org/apache/shiro/openid4j/DefaultOpenIdService.java b/support/openid4j/src/main/java/org/apache/shiro/openid4j/DefaultOpenIdService.java
new file mode 100644
index 0000000..067e3e4
--- /dev/null
+++ b/support/openid4j/src/main/java/org/apache/shiro/openid4j/DefaultOpenIdService.java
@@ -0,0 +1,148 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 org.apache.shiro.openid4j;
+
+import org.apache.shiro.util.CollectionUtils;
+import org.apache.shiro.util.StringUtils;
+import org.openid4java.OpenIDException;
+import org.openid4java.consumer.ConsumerException;
+import org.openid4java.consumer.ConsumerManager;
+import org.openid4java.discovery.DiscoveryInformation;
+import org.openid4java.message.AuthRequest;
+import org.openid4java.message.MessageException;
+import org.openid4java.message.MessageExtension;
+
+import java.util.Collection;
+import java.util.List;
+
+/**
+ * Default implementation of the {@link OpenIdService} interface.
+ *
+ * @since 1.2
+ */
+public class DefaultOpenIdService implements OpenIdService {
+
+    private ConsumerManager consumerManager;
+    private DiscoveryIdResolver discoveryIdResolver;
+    private Collection<MessageExtensionFactory> messageExtensionFactories;
+
+
+    public DefaultOpenIdService() {
+        try {
+            //The ConsumerManager class is frustrating - at the time of this implementation
+            //(2011.02.18), this constructor's source code never throws a ConsumerException - probably left in
+            //place to be backwards compatible with a previous release that did throw that exception.
+            //Another failing of checked exceptions and not programming to interfaces...
+            this.consumerManager = new ConsumerManager();
+        } catch (ConsumerException e) {
+            throw new IllegalStateException(e);
+        }
+    }
+
+    public ConsumerManager getConsumerManager() {
+        return consumerManager;
+    }
+
+    public void setConsumerManager(ConsumerManager consumerManager) {
+        this.consumerManager = consumerManager;
+    }
+
+    public DiscoveryIdResolver getDiscoveryIdResolver() {
+        return discoveryIdResolver;
+    }
+
+    public void setDiscoveryIdResolver(DiscoveryIdResolver discoveryIdResolver) {
+        this.discoveryIdResolver = discoveryIdResolver;
+    }
+
+    public Collection<MessageExtensionFactory> getMessageExtensionFactories() {
+        return messageExtensionFactories;
+    }
+
+    public void setMessageExtensionFactories(Collection<MessageExtensionFactory> messageExtensionFactories) {
+        this.messageExtensionFactories = messageExtensionFactories;
+    }
+
+    public ConstructedRequest constructRequest(String providerId, String responseUrl) throws OpenIdException {
+        String discoveryId = getDiscoveryId(providerId);
+
+        DiscoveryInformation discoveryInfo = getDiscoveryInfo(discoveryId, providerId);
+
+        AuthRequest request = createRequest(discoveryInfo, responseUrl);
+
+        addExtensions(request, discoveryInfo, providerId, discoveryId);
+
+        return createConstructedRequest(request, discoveryInfo, providerId, discoveryId);
+    }
+
+    private void addExtensions(AuthRequest request, DiscoveryInformation info, String serviceId, String discoveryId) {
+        if (!CollectionUtils.isEmpty(this.messageExtensionFactories)) {
+            for( MessageExtensionFactory factory : this.messageExtensionFactories ) {
+                MessageExtension extension = factory.createMessageExtension(request, info, serviceId, discoveryId);
+                if (extension != null) {
+                    try {
+                        request.addExtension(extension);
+                    } catch (MessageException e) {
+                        String msg = "Unable to add message extension.";
+                        throw new OpenIdException(msg, e);
+                    }
+                }
+            }
+        }
+    }
+
+    protected String getDiscoveryId(String providerId) {
+        String discoveryId = providerId;
+        if (this.discoveryIdResolver != null) {
+            discoveryId = this.discoveryIdResolver.resolveDiscoveryId(providerId);
+            if (!StringUtils.hasText(discoveryId)) {
+                throw new IllegalStateException("DiscoveryIdResolver returned a null, blank or empty string.");
+            }
+        } else {
+            if (!StringUtils.hasText(providerId)) {
+                throw new IllegalArgumentException("providerId argument cannot be null, empty or blank.");
+            }
+        }
+        return discoveryId;
+    }
+
+    protected DiscoveryInformation getDiscoveryInfo(String discoveryId, String providerId) throws DiscoveryException {
+        try {
+            List discoveries = consumerManager.discover(discoveryId);
+            return consumerManager.associate(discoveries);
+        } catch (OpenIDException e) {
+            String msg = "Unable to discover OpenId Provider based on resolved discoveryId '" + discoveryId + "' " +
+                    "(specified providerId '" + providerId + "')";
+            throw new DiscoveryException(msg, e);
+        }
+    }
+
+    protected AuthRequest createRequest(DiscoveryInformation info, String responseUrl) throws OpenIdException {
+        try {
+            return consumerManager.authenticate(info, responseUrl);
+        } catch (OpenIDException e) {
+            throw new OpenIdException("Unable to create AuthRequest.", e);
+        }
+    }
+
+    protected ConstructedRequest createConstructedRequest(AuthRequest request, DiscoveryInformation info,
+                                                          String providerId, String discoveryId) {
+        return new SimpleConstructedRequest(request, info);
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/aef52690/support/openid4j/src/main/java/org/apache/shiro/openid4j/DiscoveryException.java
----------------------------------------------------------------------
diff --git a/support/openid4j/src/main/java/org/apache/shiro/openid4j/DiscoveryException.java b/support/openid4j/src/main/java/org/apache/shiro/openid4j/DiscoveryException.java
new file mode 100644
index 0000000..c524c79
--- /dev/null
+++ b/support/openid4j/src/main/java/org/apache/shiro/openid4j/DiscoveryException.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 org.apache.shiro.openid4j;
+
+/**
+ * @since 1.2
+ */
+public class DiscoveryException extends OpenIdException {
+
+    public DiscoveryException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/aef52690/support/openid4j/src/main/java/org/apache/shiro/openid4j/DiscoveryIdResolver.java
----------------------------------------------------------------------
diff --git a/support/openid4j/src/main/java/org/apache/shiro/openid4j/DiscoveryIdResolver.java b/support/openid4j/src/main/java/org/apache/shiro/openid4j/DiscoveryIdResolver.java
new file mode 100644
index 0000000..dc0fa63
--- /dev/null
+++ b/support/openid4j/src/main/java/org/apache/shiro/openid4j/DiscoveryIdResolver.java
@@ -0,0 +1,27 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 org.apache.shiro.openid4j;
+
+/**
+ * @since 1.2
+ */
+public interface DiscoveryIdResolver {
+
+    String resolveDiscoveryId(String id);
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/aef52690/support/openid4j/src/main/java/org/apache/shiro/openid4j/MessageExtensionFactory.java
----------------------------------------------------------------------
diff --git a/support/openid4j/src/main/java/org/apache/shiro/openid4j/MessageExtensionFactory.java b/support/openid4j/src/main/java/org/apache/shiro/openid4j/MessageExtensionFactory.java
new file mode 100644
index 0000000..fc82298
--- /dev/null
+++ b/support/openid4j/src/main/java/org/apache/shiro/openid4j/MessageExtensionFactory.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 org.apache.shiro.openid4j;
+
+import org.openid4java.discovery.DiscoveryInformation;
+import org.openid4java.message.AuthRequest;
+import org.openid4java.message.MessageExtension;
+
+/**
+ * @since 1.2
+ */
+public interface MessageExtensionFactory<T extends MessageExtension> {
+
+    T createMessageExtension(AuthRequest request, DiscoveryInformation info, String serviceId, String discoveryId);
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/aef52690/support/openid4j/src/main/java/org/apache/shiro/openid4j/OpenIdException.java
----------------------------------------------------------------------
diff --git a/support/openid4j/src/main/java/org/apache/shiro/openid4j/OpenIdException.java b/support/openid4j/src/main/java/org/apache/shiro/openid4j/OpenIdException.java
new file mode 100644
index 0000000..8c0d704
--- /dev/null
+++ b/support/openid4j/src/main/java/org/apache/shiro/openid4j/OpenIdException.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 org.apache.shiro.openid4j;
+
+import org.apache.shiro.authc.AuthenticationException;
+
+/**
+ * @since 1.2
+ */
+public class OpenIdException extends AuthenticationException {
+
+    public OpenIdException(String message, Throwable cause) {
+        super(message, cause);
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/aef52690/support/openid4j/src/main/java/org/apache/shiro/openid4j/OpenIdService.java
----------------------------------------------------------------------
diff --git a/support/openid4j/src/main/java/org/apache/shiro/openid4j/OpenIdService.java b/support/openid4j/src/main/java/org/apache/shiro/openid4j/OpenIdService.java
new file mode 100644
index 0000000..6d7b5ac
--- /dev/null
+++ b/support/openid4j/src/main/java/org/apache/shiro/openid4j/OpenIdService.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 org.apache.shiro.openid4j;
+
+/**
+ * @since 1.2
+ */
+public interface OpenIdService {
+
+    ConstructedRequest constructRequest(String providerId, String responseUrl) throws OpenIdException;
+
+
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/aef52690/support/openid4j/src/main/java/org/apache/shiro/openid4j/SimpleConstructedRequest.java
----------------------------------------------------------------------
diff --git a/support/openid4j/src/main/java/org/apache/shiro/openid4j/SimpleConstructedRequest.java b/support/openid4j/src/main/java/org/apache/shiro/openid4j/SimpleConstructedRequest.java
new file mode 100644
index 0000000..d2fda21
--- /dev/null
+++ b/support/openid4j/src/main/java/org/apache/shiro/openid4j/SimpleConstructedRequest.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 org.apache.shiro.openid4j;
+
+import org.openid4java.discovery.DiscoveryInformation;
+import org.openid4java.message.AuthRequest;
+
+/**
+ * @since 1.2
+ */
+public class SimpleConstructedRequest implements ConstructedRequest {
+
+    private final DiscoveryInformation discoveryInfo;
+    private final AuthRequest authenticationRequest;
+
+    public SimpleConstructedRequest(AuthRequest authRequest, DiscoveryInformation info) {
+        this.authenticationRequest = authRequest;
+        this.discoveryInfo = info;
+    }
+
+    public DiscoveryInformation getDiscoveryInfo() {
+        return discoveryInfo;
+    }
+
+    public AuthRequest getAuthenticationRequest() {
+        return authenticationRequest;
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/aef52690/support/openid4j/src/main/java/org/apache/shiro/openid4j/ax/AttributeDefinition.java
----------------------------------------------------------------------
diff --git a/support/openid4j/src/main/java/org/apache/shiro/openid4j/ax/AttributeDefinition.java b/support/openid4j/src/main/java/org/apache/shiro/openid4j/ax/AttributeDefinition.java
new file mode 100644
index 0000000..787c56e
--- /dev/null
+++ b/support/openid4j/src/main/java/org/apache/shiro/openid4j/ax/AttributeDefinition.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 org.apache.shiro.openid4j.ax;
+
+/**
+ * @since 1.2
+ */
+public interface AttributeDefinition {
+
+    String getName();
+
+    String getUri();
+
+    boolean isRequired();
+
+    int getCount();
+
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/aef52690/support/openid4j/src/main/java/org/apache/shiro/openid4j/ax/AttributeProperty.java
----------------------------------------------------------------------
diff --git a/support/openid4j/src/main/java/org/apache/shiro/openid4j/ax/AttributeProperty.java b/support/openid4j/src/main/java/org/apache/shiro/openid4j/ax/AttributeProperty.java
new file mode 100644
index 0000000..8f7714b
--- /dev/null
+++ b/support/openid4j/src/main/java/org/apache/shiro/openid4j/ax/AttributeProperty.java
@@ -0,0 +1,118 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 org.apache.shiro.openid4j.ax;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * An Enum representing all de-facto standard <a href="http://www.axschema.org/types/">
+ * Attribute Exchange Types</a>.
+ *
+ * @since 1.2
+ */
+public enum AttributeProperty {
+
+    Username("http://axschema.org/namePerson/friendly", "Alias/Username"),
+    FullName("http://axschema.org/namePerson", "Full name"),
+    NamePrefix("http://axschema.org/namePerson/prefix", "Name prefix"),
+    FirstName("http://axschema.org/namePerson/first", "First name"),
+    LastName("http://axschema.org/namePerson/last", "Last name"),
+    MiddleName("http://axschema.org/namePerson/middle", "Middle name"),
+    NameSuffix("http://axschema.org/namePerson/suffix", "Name suffix"),
+    CompanyName("http://axschema.org/company/name", "Company name"),
+    JobTitle("http://axschema.org/company/title", "Job title"),
+    BirthDate("http://axschema.org/birthDate", "Birth date"),
+    BirthYear("http://axschema.org/birthDate/birthYear", "Birth year"),
+    BirthMonth("http://axschema.org/birthDate/birthMonth", "Birth month"),
+    BirthDay("http://axschema.org/birthDate/birthday", "Birth day"),
+    PhonePreferred("http://axschema.org/contact/phone/default", "Phone (preferred)"),
+    PhoneHome("http://axschema.org/contact/phone/home", "Phone (home)"),
+    PhoneWork("http://axschema.org/contact/phone/business", "Phone (work)"),
+    PhoneMobile("http://axschema.org/contact/phone/cell", "Phone (mobile)"),
+    PhoneFax("http://axschema.org/contact/phone/fax", "Phone (fax)"),
+    Address("http://axschema.org/contact/postalAddress/home", "Address"),
+    Address2("http://axschema.org/contact/postalAddressAdditional/home", "Address 2"),
+    City("http://axschema.org/contact/city/home", "City"),
+    State("http://axschema.org/contact/state/home", "State/Province"),
+    Country("http://axschema.org/contact/country/home", "Country"),
+    PostalCode("http://axschema.org/contact/postalCode/home", "Postal code"),
+    BusinessAddress("http://axschema.org/contact/postalAddress/business", "Address"),
+    BusinessAddress2("http://axschema.org/contact/postalAddressAdditional/business", "Address 2"),
+    BusinessCity("http://axschema.org/contact/city/business", "City"),
+    BusinessState("http://axschema.org/contact/state/business", "State/Province"),
+    BusinessCountry("http://axschema.org/contact/country/business", "Country"),
+    BusinessPostalCode("http://axschema.org/contact/postalCode/business", "Postal code"),
+    Email("http://axschema.org/contact/email", "Email"),
+    AOLIM("http://axschema.org/contact/IM/AIM", "AOL IM"),
+    ICQIM("http://axschema.org/contact/IM/ICQ", "ICQ IM"),
+    MSNIM("http://axschema.org/contact/IM/MSN", "MSN IM"),
+    YahooIM("http://axschema.org/contact/IM/Yahoo", "Yahoo! IM"),
+    JabberIM("http://axschema.org/contact/IM/Jabber", "Jabber IM"),
+    SkypeIM("http://axschema.org/contact/IM/Skype", "Skype IM"),
+    WebPage("http://axschema.org/contact/web/default", "Web page"),
+    Blog("http://axschema.org/contact/web/blog", "Blog"),
+    LinkedInURL("http://axschema.org/contact/web/Linkedin", "LinkedIn URL"),
+    AmazonURL("http://axschema.org/contact/web/Amazon", "Amazon URL"),
+    FlickrURL("http://axschema.org/contact/web/Flickr", "Flickr URL"),
+    DeliciousURL("http://axschema.org/contact/web/Delicious", "del.icio.us URL"),
+    SpokenName("http://axschema.org/media/spokenname", "Spoken name"),
+    AudioGreeting("http://axschema.org/media/greeting/audio", "Audio greeting"),
+    VideoGreeting("http://axschema.org/media/greeting/video", "Video greeting"),
+    Image("http://axschema.org/media/image/default", "Image"),
+    SquareImage("http://axschema.org/media/image/aspect11", "Square image"),
+    Aspect43Image("http://axschema.org/media/image/aspect43", "4:3 aspect image"),
+    Aspect34Image("http://axschema.org/media/image/aspect34", "3:4 aspect image"),
+    FaviconImage("http://axschema.org/media/image/favicon", "Favicon image"),
+    Gender("http://axschema.org/person/gender", "Gender"),
+    Language("http://axschema.org/pref/language", "Language"),
+    TimeZone("http://axschema.org/pref/timezone", "Time zone");
+
+    private static final Map<String, AttributeProperty> caseInsensitiveNameMap;
+
+    static {
+        caseInsensitiveNameMap = new HashMap<String, AttributeProperty>();
+        for (AttributeProperty prop : values()) {
+            caseInsensitiveNameMap.put(prop.name().toLowerCase(), prop);
+        }
+    }
+
+    private final String label;
+    private final String uri;
+
+    private AttributeProperty(String uri, String label) {
+        this.uri = uri;
+        this.label = label;
+    }
+
+    public static AttributeProperty fromName(String caseInsensitiveName) {
+        if (caseInsensitiveName == null) {
+            return null;
+        }
+        return caseInsensitiveNameMap.get(caseInsensitiveName.toLowerCase());
+    }
+
+    public String getLabel() {
+        return label;
+    }
+
+    public String getUri() {
+        return uri;
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/aef52690/support/openid4j/src/main/java/org/apache/shiro/openid4j/ax/FetchRequestFactory.java
----------------------------------------------------------------------
diff --git a/support/openid4j/src/main/java/org/apache/shiro/openid4j/ax/FetchRequestFactory.java b/support/openid4j/src/main/java/org/apache/shiro/openid4j/ax/FetchRequestFactory.java
new file mode 100644
index 0000000..499119a
--- /dev/null
+++ b/support/openid4j/src/main/java/org/apache/shiro/openid4j/ax/FetchRequestFactory.java
@@ -0,0 +1,164 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 org.apache.shiro.openid4j.ax;
+
+import org.apache.shiro.config.ConfigurationException;
+import org.apache.shiro.openid4j.MessageExtensionFactory;
+import org.apache.shiro.openid4j.OpenIdException;
+import org.apache.shiro.util.StringUtils;
+import org.openid4java.discovery.DiscoveryInformation;
+import org.openid4java.message.AuthRequest;
+import org.openid4java.message.MessageException;
+import org.openid4java.message.ax.FetchRequest;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * @since 1.2
+ */
+public class FetchRequestFactory implements MessageExtensionFactory<FetchRequest> {
+
+    private static final Logger log = LoggerFactory.getLogger(FetchRequestFactory.class);
+
+    private Map<String, String> providerAttributes;
+
+    public FetchRequestFactory() {
+        this.providerAttributes = new HashMap<String,String>();
+    }
+
+    public Map<String, String> getProviderAttributes() {
+        return providerAttributes;
+    }
+
+    public void setProviderAttributes(Map<String, String> providerAttributes) {
+        this.providerAttributes = providerAttributes;
+    }
+
+    public FetchRequest createMessageExtension(AuthRequest request, DiscoveryInformation info, String serviceId, String discoveryId) {
+
+        String definition = providerAttributes.get(serviceId);
+        if (definition == null) {
+            definition = providerAttributes.get(discoveryId);
+        }
+        if (definition == null) {
+            return null;
+        }
+
+        String[] attributes = StringUtils.split(definition);
+        if (attributes == null || attributes.length == 0) {
+            return null;
+        }
+
+        FetchRequest fetch = FetchRequest.createFetchRequest();
+
+        //parse the definition by tokenizing it to get the resulting attribute-specific config
+        //
+        //e.g. for a value of
+        //
+        //     "email, firstName[required=true], lastName"
+        //
+        // the resulting token array would equal
+        //
+        //     { "email", "firstName[required=true]", "lastName" }
+        //
+        for (String attribute : attributes) {
+            //strip the name and extract any attribute-specific config between brackets [ ]
+            String[] nameAndConfig = attribute.split("\\[", 2);
+            String name = nameAndConfig[0];
+            String config = null;
+
+            if (nameAndConfig.length == 2) {
+                config = nameAndConfig[1];
+                //if there was an open bracket, there was a close bracket, so strip it too:
+                config = config.substring(0, config.length() - 1);
+            }
+
+            AttributeDefinition ad = toDefinition(name, config);
+
+            try {
+                fetch.addAttribute(ad.getName(), ad.getUri(), ad.isRequired(), ad.getCount());
+            } catch (MessageException e) {
+                throw new OpenIdException("Unable to correctly add 'fetch' attribute.", e);
+            }
+        }
+
+        return fetch;
+    }
+
+    protected AttributeDefinition toDefinition(String name, String config) {
+
+        AttributeProperty prop = AttributeProperty.fromName(name);
+        if (prop == null) {
+            throw new ConfigurationException("Unable to locate a standard OpenId Attribute property for name '" +
+                    name + "'.  Please ensure this name matches one of the constants in the " +
+                    AttributeProperty.class.getName() + " enum (name matching is case insensitive).");
+        }
+
+        String uri = prop.getUri();
+        boolean required = false;
+        int count = 0;
+
+
+        if (config != null) {
+            String[] configPairs = StringUtils.split(config);
+            for (String pair : configPairs) {
+                String nameValue[] = pair.split("\\=", 2);
+                if (nameValue.length != 2) {
+                    throw new ConfigurationException("OpenId attribute properties with configuration must be " +
+                            "comma-delimited name/value pairs.  Each name/value pair must be separated by the " +
+                            "equals sign, e.g. nameProp[name1=value1, name2=value2, ...].   The string that " +
+                            "caused this error was '" + pair + "'.");
+                }
+                String pairName = nameValue[0];
+                String pairValue = nameValue[1];
+
+                if ("uri".equalsIgnoreCase(pairName)) {
+                    uri = pairValue;
+                } else if ("required".equalsIgnoreCase(pairName)) {
+                    required = Boolean.valueOf(pairValue);
+                } else if ("count".equalsIgnoreCase(pairName)) {
+                    try {
+                        count = Integer.parseInt(pairValue);
+                    } catch (NumberFormatException e) {
+                        String msg = "Unable to correctly parse 'count' value '" + pairValue + "' for OpenId " +
+                                "attribute '" + name + "'";
+                        throw new ConfigurationException(msg, e);
+                    }
+                    if (count < 0) {
+                        count = 0;
+                    }
+                } else {
+                    if (log.isWarnEnabled()) {
+                        log.warn("Unrecognized configuration name/value pair for OpenId attribute '{}': {}={}",
+                                new Object[]{name, pairName, pairValue});
+                    }
+
+                }
+            }
+        }
+
+
+        return new SimpleAttributeDefinition(prop.name(), uri, required, count);
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/aef52690/support/openid4j/src/main/java/org/apache/shiro/openid4j/ax/SimpleAttributeDefinition.java
----------------------------------------------------------------------
diff --git a/support/openid4j/src/main/java/org/apache/shiro/openid4j/ax/SimpleAttributeDefinition.java b/support/openid4j/src/main/java/org/apache/shiro/openid4j/ax/SimpleAttributeDefinition.java
new file mode 100644
index 0000000..bd7de70
--- /dev/null
+++ b/support/openid4j/src/main/java/org/apache/shiro/openid4j/ax/SimpleAttributeDefinition.java
@@ -0,0 +1,74 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 org.apache.shiro.openid4j.ax;
+
+import org.apache.shiro.openid4j.ax.AttributeDefinition;
+
+/**
+ * @since 1.2
+ */
+public class SimpleAttributeDefinition implements AttributeDefinition {
+
+    private String name;
+    private String uri;
+    private boolean required;
+    private int count;
+
+    public SimpleAttributeDefinition() {
+    }
+
+    public SimpleAttributeDefinition(String name, String uri, boolean required, int count) {
+        this.name = name;
+        this.uri = uri;
+        this.required = required;
+        this.count = count;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getUri() {
+        return uri;
+    }
+
+    public void setUri(String uri) {
+        this.uri = uri;
+    }
+
+    public boolean isRequired() {
+        return required;
+    }
+
+    public void setRequired(boolean required) {
+        this.required = required;
+    }
+
+    public int getCount() {
+        return count;
+    }
+
+    public void setCount(int count) {
+        this.count = count;
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/aef52690/support/openid4j/src/main/java/org/apache/shiro/openid4j/realm/RelyingPartyRealm.java
----------------------------------------------------------------------
diff --git a/support/openid4j/src/main/java/org/apache/shiro/openid4j/realm/RelyingPartyRealm.java b/support/openid4j/src/main/java/org/apache/shiro/openid4j/realm/RelyingPartyRealm.java
new file mode 100644
index 0000000..8f65006
--- /dev/null
+++ b/support/openid4j/src/main/java/org/apache/shiro/openid4j/realm/RelyingPartyRealm.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 org.apache.shiro.openid4j.realm;
+
+import org.apache.shiro.authc.AuthenticationException;
+import org.apache.shiro.authc.AuthenticationInfo;
+import org.apache.shiro.authc.AuthenticationToken;
+import org.apache.shiro.openid4j.OpenIdService;
+import org.apache.shiro.realm.AuthenticatingRealm;
+
+/**
+ * A {@code Realm} implementation that performs OpenID authentication by acting as the &quot;Relying Party&quot;
+ * (client) to an OpenId Provider (server).
+ *
+ * @since 1.2
+ */
+public class RelyingPartyRealm extends AuthenticatingRealm {
+
+    private OpenIdService openIdService;
+
+    public RelyingPartyRealm() {
+
+    }
+
+    public OpenIdService getOpenIdService() {
+        return openIdService;
+    }
+
+    public void setOpenIdService(OpenIdService openIdService) {
+        this.openIdService = openIdService;
+    }
+
+    @Override
+    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
+
+        //TODO
+
+        return null;
+
+    }
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/aef52690/support/openid4j/src/test/groovy/AttributeTypeScreenScraper.groovy
----------------------------------------------------------------------
diff --git a/support/openid4j/src/test/groovy/AttributeTypeScreenScraper.groovy b/support/openid4j/src/test/groovy/AttributeTypeScreenScraper.groovy
new file mode 100644
index 0000000..d11a8bc
--- /dev/null
+++ b/support/openid4j/src/test/groovy/AttributeTypeScreenScraper.groovy
@@ -0,0 +1,100 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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.
+ */
+
+/**
+ * @since 1.2
+ */
+class AttributeTypeScreenScraper extends GroovyTestCase {
+
+    void testNothing() {}
+
+    //used to generate constants in the AttributeProperty class:
+    void doTestScrape() {
+
+        //file copied from the OpenId website:
+        def resource = "http://www.axschema.org/types/";
+
+        def properties = []
+        def property = [:]
+
+        boolean parsing = false;
+
+        resource.toURL().eachLine("UTF-8", { String line ->
+
+            line = line.trim()
+
+            if (line.equals("<table id=\"types\">")) {
+                parsing = true;
+            }
+            if (parsing && line.equals("</table>")) {
+                parsing = false
+            }
+            if (parsing) {
+                if (line.equals("<tr>") && property.size() == 3) {
+                    properties << property
+                    property = [:]
+                }
+                if (line.startsWith("<td") && line.endsWith("</a></td>")) {
+                    int index = line.lastIndexOf("http://");
+                    line = line.substring(index, line.length() - "</a></td>".length())
+                    property.uri = line
+                } else if (line.startsWith("<td>") && line.endsWith("</td>") && !line.contains("&nbsp;")) {
+                    line = line.substring(4, line.length() - 5)
+                    property.label = line
+
+                    String[] words = property.label.split(" ");
+                    String varName = "";
+                    for( String s : words ) {
+                        s = s.replace("(", "")
+                        s = s.replace(")", "")
+                        s = s.replace(".", "")
+                        int index = s.indexOf("/")
+                        if (index > 0) {
+                            s = s.substring(0, index)
+                        }
+                        varName += s.capitalize()
+                    }
+
+                    //special cases:
+                    if (property.uri.endsWith("business")) {
+                        varName = "Business" + varName;
+                    }
+                    if (varName == "Alias") {
+                        varName = "Username"
+                    }
+                    if (varName == "Yahoo!IM") {
+                        varName = "YahooIM"
+                    }
+                    if (varName == "4:3AspectImage") {
+                        varName = "Aspect43Image"
+                    }
+                    if (varName == "3:4AspectImage") {
+                        varName = "Aspect34Image"
+                    }
+                    property.name = varName;
+                }
+            }
+        });
+        for (def prop: properties) {
+            String d = "${prop.name}(\"${prop.uri}\", \"${prop.label}\"), ";
+            System.out.println(d);
+        }
+    }
+
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/aef52690/support/openid4j/src/test/groovy/org/apache/shiro/openid4j/ax/FetchRequestFactoryTest.groovy
----------------------------------------------------------------------
diff --git a/support/openid4j/src/test/groovy/org/apache/shiro/openid4j/ax/FetchRequestFactoryTest.groovy b/support/openid4j/src/test/groovy/org/apache/shiro/openid4j/ax/FetchRequestFactoryTest.groovy
new file mode 100644
index 0000000..7d72fc4
--- /dev/null
+++ b/support/openid4j/src/test/groovy/org/apache/shiro/openid4j/ax/FetchRequestFactoryTest.groovy
@@ -0,0 +1,47 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements.  See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership.  The ASF 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 org.apache.shiro.openid4j.ax
+
+import org.openid4java.message.ax.FetchRequest
+
+/**
+ * Created by IntelliJ IDEA.
+ * User: lhazlewood
+ * Date: 2/21/11
+ * Time: 10:04 PM
+ * To change this template use File | Settings | File Templates.
+ */
+class FetchRequestFactoryTest extends GroovyTestCase {
+
+    void testCreateWithProviderAttributes() {
+
+        FetchRequestFactory factory = new FetchRequestFactory();
+
+        factory.providerAttributes.google = "email[count=1], firstName[required=true], lastName"
+
+        FetchRequest request = factory.createMessageExtension(null, null, "google", null);
+
+        assertNotNull request
+        def list = request.getParameters();
+        System.out.println(list);
+
+    }
+
+
+}

http://git-wip-us.apache.org/repos/asf/shiro/blob/aef52690/support/openid4j/src/test/resources/log4j.properties
----------------------------------------------------------------------
diff --git a/support/openid4j/src/test/resources/log4j.properties b/support/openid4j/src/test/resources/log4j.properties
new file mode 100644
index 0000000..0d51520
--- /dev/null
+++ b/support/openid4j/src/test/resources/log4j.properties
@@ -0,0 +1,37 @@
+#
+# Licensed to the Apache Software Foundation (ASF) under one
+# or more contributor license agreements.  See the NOTICE file
+# distributed with this work for additional information
+# regarding copyright ownership.  The ASF 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.
+#
+
+log4j.rootLogger=TRACE, stdout
+
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n
+
+# Pattern to output: date priority [category] - message
+log4j.appender.logfile.layout=org.apache.log4j.PatternLayout
+log4j.appender.logfile.layout.ConversionPattern=%d %p [%c] - %m%n
+
+# Spring logging level is WARN
+log4j.logger.net.sf.ehcache=INFO
+
+# General Apache libraries is WARN
+log4j.logger.org.apache=WARN
+
+log4j.logger.org.apache.shiro=TRACE
+log4j.logger.org.apache.shiro.util.ThreadContext=WARN
\ No newline at end of file

http://git-wip-us.apache.org/repos/asf/shiro/blob/aef52690/support/pom.xml
----------------------------------------------------------------------
diff --git a/support/pom.xml b/support/pom.xml
index 8886f02..fd7f801 100644
--- a/support/pom.xml
+++ b/support/pom.xml
@@ -38,6 +38,7 @@
         <module>quartz</module>
         <module>spring</module>
         <module>guice</module>
+        <module>openid4j</module>
         <module>features</module>
         <module>cas</module>
         <module>spring-boot</module>