├── samples ├── DynamicRegistrationAppAuthDemo-Android │ ├── app │ │ ├── .gitignore │ │ ├── src │ │ │ ├── main │ │ │ │ ├── res │ │ │ │ │ ├── mipmap-hdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-mdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── mipmap-xxxhdpi │ │ │ │ │ │ └── ic_launcher.png │ │ │ │ │ ├── drawable │ │ │ │ │ │ ├── btn_omnissa_signin_focus.9.png │ │ │ │ │ │ ├── btn_omnissa_signin_normal.9.png │ │ │ │ │ │ ├── btn_omnissa_signin_pressed.9.png │ │ │ │ │ │ ├── btn_omnissa.xml │ │ │ │ │ │ ├── unknown_user_48dp.xml │ │ │ │ │ │ └── openid_96dp.xml │ │ │ │ │ ├── values │ │ │ │ │ │ ├── dimens.xml │ │ │ │ │ │ ├── colors.xml │ │ │ │ │ │ ├── styles.xml │ │ │ │ │ │ ├── idp_configs.xml │ │ │ │ │ │ ├── idp_configs_optional.xml │ │ │ │ │ │ └── strings.xml │ │ │ │ │ ├── values-w820dp │ │ │ │ │ │ └── dimens.xml │ │ │ │ │ ├── activity_main.xml │ │ │ │ │ ├── layout │ │ │ │ │ │ ├── activity_main.xml │ │ │ │ │ │ └── activity_token.xml │ │ │ │ │ └── activity_token.xml │ │ │ │ ├── java │ │ │ │ │ ├── com │ │ │ │ │ │ └── omnissa │ │ │ │ │ │ │ └── idm │ │ │ │ │ │ │ └── samples │ │ │ │ │ │ │ └── appauth │ │ │ │ │ │ │ ├── package-info.java │ │ │ │ │ │ │ └── Application.java │ │ │ │ │ └── net │ │ │ │ │ │ └── openid │ │ │ │ │ │ └── appauth │ │ │ │ │ │ ├── DeviceRegistrationPendingIntentStore.java │ │ │ │ │ │ ├── RedirectUriRegistrationReceiverActivity.java │ │ │ │ │ │ ├── DeviceActivationResponse.java │ │ │ │ │ │ ├── DeviceRegistrationResponse.java │ │ │ │ │ │ └── DeviceActivationRequest.java │ │ │ │ └── AndroidManifest.xml │ │ │ └── test │ │ │ │ └── java │ │ │ │ └── net │ │ │ │ └── openid │ │ │ │ └── appauth │ │ │ │ ├── OmnissaAppAuthTest.java │ │ │ │ ├── DeviceActivationResponseTest.java │ │ │ │ ├── DeviceActivationRequestTest.java │ │ │ │ ├── RedirectUriRegistrationReceiverActivityTest.java │ │ │ │ ├── DeviceRegistrationRequestTest.java │ │ │ │ └── DeviceRegistrationResponseTest.java │ │ ├── proguard-rules.pro │ │ └── build.gradle │ ├── settings.gradle │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── .gitignore │ ├── build.gradle │ ├── gradle.properties │ ├── gradlew.bat │ ├── README.md │ └── gradlew ├── webapp-spring-boot-saml2 │ ├── images │ │ ├── CreateSAML2App.png │ │ ├── EditSAML2App.png │ │ └── ConfigureSAML2App.png │ ├── gradle │ │ └── wrapper │ │ │ ├── gradle-wrapper.jar │ │ │ └── gradle-wrapper.properties │ ├── src │ │ ├── main │ │ │ ├── resources │ │ │ │ ├── saml │ │ │ │ │ ├── samlKeystore.jks │ │ │ │ │ └── update-certificate.sh │ │ │ │ ├── application.properties │ │ │ │ ├── templates │ │ │ │ │ ├── error.html │ │ │ │ │ ├── index.html │ │ │ │ │ ├── landing.html │ │ │ │ │ └── saml │ │ │ │ │ │ └── idpselection.html │ │ │ │ └── log4j.properties │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── omnissa │ │ │ │ └── idm │ │ │ │ └── samples │ │ │ │ └── saml │ │ │ │ ├── Application.java │ │ │ │ ├── stereotypes │ │ │ │ └── CurrentUser.java │ │ │ │ ├── controllers │ │ │ │ ├── LandingController.java │ │ │ │ └── SSOController.java │ │ │ │ ├── config │ │ │ │ └── MvcConfig.java │ │ │ │ └── core │ │ │ │ ├── CurrentUserHandlerMethodArgumentResolver.java │ │ │ │ └── SAMLUserDetailsServiceImpl.java │ │ └── test │ │ │ ├── resources │ │ │ └── log4j.properties │ │ │ └── java │ │ │ └── com │ │ │ └── omnissa │ │ │ └── idm │ │ │ └── samples │ │ │ └── saml │ │ │ ├── core │ │ │ ├── SAMLUserDetailsServiceImplTest.java │ │ │ └── CurrentUserHandlerMethodArgumentResolverTest.java │ │ │ ├── controllers │ │ │ ├── SSOControllerTest.java │ │ │ └── LandingControllerTest.java │ │ │ └── CommonTestSupport.java │ ├── build.gradle │ ├── gradlew.bat │ ├── README.md │ └── gradlew ├── webapp-spring-boot-oauth2-resource-server │ ├── src │ │ ├── main │ │ │ ├── resources │ │ │ │ └── application.yml │ │ │ └── java │ │ │ │ └── com │ │ │ │ └── omnissa │ │ │ │ └── idm │ │ │ │ └── samples │ │ │ │ └── oauth2 │ │ │ │ ├── ResourceApplication.java │ │ │ │ ├── OmnissaValidateTokenServices.java │ │ │ │ └── ResourceApplicationConfiguration.java │ │ └── test │ │ │ └── java │ │ │ └── com │ │ │ └── omnissa │ │ │ └── idm │ │ │ └── samples │ │ │ └── oauth2 │ │ │ └── ResourceApplicationTest.java │ ├── pom.xml │ └── README.md └── webapp-spring-boot-oauth2 │ ├── src │ ├── main │ │ ├── resources │ │ │ ├── application.yml │ │ │ └── static │ │ │ │ └── index.html │ │ └── java │ │ │ └── com │ │ │ └── omnissa │ │ │ └── idm │ │ │ └── samples │ │ │ └── oauth2 │ │ │ └── SocialApplication.java │ └── test │ │ └── java │ │ └── com │ │ └── omnissa │ │ └── idm │ │ └── samples │ │ └── oauth2 │ │ ├── OmnissaPrincipalExtractorTest.java │ │ └── SocialApplicationTests.java │ ├── README.md │ └── pom.xml ├── .travis.yml ├── LICENSE ├── CONTRIBUTING.md └── README.md /samples/DynamicRegistrationAppAuthDemo-Android/app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/images/CreateSAML2App.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnissa-archive/idm/master/samples/webapp-spring-boot-saml2/images/CreateSAML2App.png -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/images/EditSAML2App.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnissa-archive/idm/master/samples/webapp-spring-boot-saml2/images/EditSAML2App.png -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/images/ConfigureSAML2App.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnissa-archive/idm/master/samples/webapp-spring-boot-saml2/images/ConfigureSAML2App.png -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnissa-archive/idm/master/samples/webapp-spring-boot-saml2/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/main/resources/saml/samlKeystore.jks: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnissa-archive/idm/master/samples/webapp-spring-boot-saml2/src/main/resources/saml/samlKeystore.jks -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnissa-archive/idm/master/samples/DynamicRegistrationAppAuthDemo-Android/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | /.idea/workspace.xml 5 | /.idea/libraries 6 | .DS_Store 7 | /build 8 | /captures 9 | .externalNativeBuild 10 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnissa-archive/idm/master/samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnissa-archive/idm/master/samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnissa-archive/idm/master/samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnissa-archive/idm/master/samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnissa-archive/idm/master/samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/drawable/btn_omnissa_signin_focus.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnissa-archive/idm/master/samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/drawable/btn_omnissa_signin_focus.9.png -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/drawable/btn_omnissa_signin_normal.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnissa-archive/idm/master/samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/drawable/btn_omnissa_signin_normal.9.png -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/drawable/btn_omnissa_signin_pressed.9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/omnissa-archive/idm/master/samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/drawable/btn_omnissa_signin_pressed.9.png -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: java 2 | env: 3 | - SAMPLE_DIR=samples/webapp-spring-boot-oauth2 4 | - SAMPLE_DIR=samples/webapp-spring-boot-oauth2-resource-server 5 | - SAMPLE_DIR=samples/webapp-spring-boot-saml2 6 | 7 | script: cd $SAMPLE_DIR && if [ -f build.gradle ]; then ./gradlew build; else mvn package; fi 8 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/main/resources/application.properties: -------------------------------------------------------------------------------- 1 | # 2 | # Application properties for demo app 3 | # 4 | 5 | # The keystore secret 6 | keystore.secret=secret 7 | 8 | # The URL to the Omnissa Identity Manager organization 9 | omnissa.url=https://dev.omnissaidentity.asia 10 | 11 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Tue May 30 14:47:40 PDT 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.5-all.zip 7 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Dec 28 10:00:20 PST 2015 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-2.14.1-all.zip 7 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 16dp 4 | 16dp 5 | 16dp 6 | 7 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | #aeafb3 5 | #7c7d80 6 | 7 | #f38019 8 | 9 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 5 | 64dp 6 | 7 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/main/resources/templates/error.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | Error! 6 | 7 | 8 |

Error!

9 |

10 | Something went wrong during the authentication process. 11 |

12 | 13 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/drawable/btn_omnissa.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 8 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/main/resources/templates/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Omnissa IDM SAML2 Sample Application 5 | 6 | 7 |

Welcome to the SAML2 sample web application!

8 |

9 | SSO Login Page 10 |

11 |

12 | Download SAML metadata XML 13 |

14 | 15 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 11 | 12 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-oauth2-resource-server/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | omnissa: 2 | resource: 3 | userInfoUri: https://dev.omnissaidentity.asia/SAAS/jersey/manager/api/userinfo 4 | checkTokenUri: https://dev.omnissaidentity.asia/SAAS/API/1.0/REST/auth/token?attribute=isValid 5 | localValidation: true 6 | id: https://dev.omnissaidentity.asia/SAAS/auth/oauthtoken 7 | jwt: 8 | keyUri: https://dev.omnissaidentity.asia/SAAS/API/1.0/REST/auth/token?attribute=publicKey 9 | 10 | logging: 11 | level: 12 | org.springframework.security: DEBUG 13 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/main/resources/templates/landing.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | Landing! 6 | 7 | 8 |

You are logged as null!

9 |

10 | Global Logout
11 | Local Logout 12 |

13 | 14 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.2.0' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-oauth2/src/main/resources/application.yml: -------------------------------------------------------------------------------- 1 | 2 | omnissa: 3 | client: 4 | clientId: webapp.samples.omnissa.com 5 | clientSecret: Gp4mGG5klyCm8k3UZwJR4o2fCL4OqwBIplRl4yvAE90MVyRg 6 | accessTokenUri: https://dev.omnissaidentity.asia/SAAS/auth/oauthtoken 7 | userAuthorizationUri: https://dev.omnissaidentity.asia/SAAS/auth/oauth2/authorize 8 | authenticationScheme: header 9 | clientAuthenticationScheme: header 10 | scope: openid 11 | resource: 12 | userInfoUri: https://dev.omnissaidentity.asia/SAAS/jersey/manager/api/userinfo 13 | 14 | 15 | logging: 16 | level: 17 | org.springframework.security: DEBUG 18 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/build.gradle: -------------------------------------------------------------------------------- 1 | plugins { 2 | id "java" 3 | id 'org.springframework.boot' version '1.5.3.RELEASE' 4 | } 5 | description = "Spring Boot SAML v2 sample webapp" 6 | 7 | repositories { 8 | jcenter() 9 | } 10 | ext { 11 | springSecuritySaml2Version = '1.0.2.RELEASE' 12 | } 13 | 14 | dependencies { 15 | 16 | compile 'org.springframework.boot:spring-boot-starter-security' 17 | compile "org.springframework.boot:spring-boot-starter-thymeleaf" 18 | 19 | // SAML2 20 | compile "org.springframework.security.extensions:spring-security-saml2-core:$springSecuritySaml2Version" 21 | 22 | // tests 23 | testCompile 'org.springframework.boot:spring-boot-starter-test' 24 | } -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in /Users/fstrudel/Library/Android/sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/main/resources/templates/saml/idpselection.html: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | Select you IdP! 6 | 7 | 8 |

Select your IdP:

9 |
10 |
11 | 12 | 13 |
14 |

15 | 16 |

17 |
18 | 19 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/drawable/unknown_user_48dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 16 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/test/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=info, stdout, R 2 | 3 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 4 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 5 | 6 | # Pattern to output the caller's file name and line number. 7 | log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n 8 | 9 | log4j.appender.R.layout=org.apache.log4j.PatternLayout 10 | log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n 11 | 12 | log4j.appender.R=org.apache.log4j.RollingFileAppender 13 | log4j.appender.R.File=logs/file.log 14 | 15 | log4j.appender.R.MaxFileSize=100KB 16 | # Keep one backup file 17 | log4j.appender.R.MaxBackupIndex=1 18 | 19 | # Application logging settings 20 | log4j.logger.org.springframework.security.saml=info 21 | log4j.logger.org.opensaml=info 22 | log4j.logger.PROTOCOL_MESSAGE=info -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/main/resources/log4j.properties: -------------------------------------------------------------------------------- 1 | log4j.rootLogger=debug, stdout, R 2 | 3 | log4j.appender.stdout=org.apache.log4j.ConsoleAppender 4 | log4j.appender.stdout.layout=org.apache.log4j.PatternLayout 5 | 6 | # Pattern to output the caller's file name and line number. 7 | log4j.appender.stdout.layout.ConversionPattern=%5p [%t] (%F:%L) - %m%n 8 | 9 | log4j.appender.R.layout=org.apache.log4j.PatternLayout 10 | log4j.appender.R.layout.ConversionPattern=%p %t %c - %m%n 11 | 12 | log4j.appender.R=org.apache.log4j.RollingFileAppender 13 | log4j.appender.R.File=logs/file.log 14 | 15 | log4j.appender.R.MaxFileSize=100KB 16 | # Keep one backup file 17 | log4j.appender.R.MaxBackupIndex=1 18 | 19 | # Application logging settings 20 | log4j.logger.org.springframework.security.saml=DEBUG 21 | log4j.logger.org.opensaml=DEBUG 22 | log4j.logger.PROTOCOL_MESSAGE=DEBUG -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/java/com/omnissa/idm/samples/appauth/package-info.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2015 The AppAuth for Android Authors. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the 10 | * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | * express or implied. See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | /** 16 | * App which demonstrates the use of the AppAuth library to authenticate a Omnissa Identity Manager account. 17 | */ 18 | package com.omnissa.idm.samples.appauth; 19 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/drawable/openid_96dp.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 14 | 21 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/main/resources/saml/update-certificate.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | set -e 3 | 4 | # Use this script to update the certificate of your Identity Provider (i.e. Omnissa Identity Manager) in the keystore 5 | # './src/main/resources/saml/samlKeystore.jks' file 6 | # Run: 7 | # $ ./src/main/resources/saml/update-certificate.sh 8 | 9 | 10 | IDP_HOST=dev.omnissaidentity.asia 11 | IDP_PORT=443 12 | CERTIFICATE_FILE=omnissa-idm.cert 13 | KEYSTORE_FILE=`dirname $0`/samlKeystore.jks 14 | KEYSTORE_PASSWORD=secret 15 | KEYSTORE_ALIAS=omnissaidm 16 | 17 | openssl s_client -host ${IDP_HOST} -port ${IDP_PORT} -prexit -showcerts ${CERTIFICATE_FILE} 18 | keytool -delete -alias ${KEYSTORE_ALIAS} -keystore ${KEYSTORE_FILE} -storepass ${KEYSTORE_PASSWORD} 19 | keytool -import -alias ${KEYSTORE_ALIAS} -file ${CERTIFICATE_FILE} -keystore ${KEYSTORE_FILE} -storepass ${KEYSTORE_PASSWORD} -noprompt 20 | 21 | rm -rf ${CERTIFICATE_FILE} 22 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/main/java/com/omnissa/idm/samples/saml/Application.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Vincenzo De Notaris 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.omnissa.idm.samples.saml; 18 | 19 | import org.springframework.boot.SpringApplication; 20 | import org.springframework.boot.autoconfigure.SpringBootApplication; 21 | 22 | @SpringBootApplication 23 | public class Application { 24 | 25 | public static void main(String[] args) { 26 | SpringApplication.run(Application.class, args); 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/values/idp_configs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | true 11 | 12 | 13 | https://dev.omnissaidentity.asia 14 | 15 | 16 | Omnissa-AppAuth-Samples-Template 17 | com.omnissa.idm.samples.mobilesso 18 | com.omnissa.idm.samples.mobilesso://oauth2redirect 19 | 20 | 21 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2016-2021 Omnissa, LLC. All rights reserved. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/main/java/com/omnissa/idm/samples/saml/stereotypes/CurrentUser.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Vincenzo De Notaris 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.omnissa.idm.samples.saml.stereotypes; 18 | 19 | import java.lang.annotation.Documented; 20 | import java.lang.annotation.Retention; 21 | import java.lang.annotation.Target; 22 | import java.lang.annotation.ElementType; 23 | import java.lang.annotation.RetentionPolicy; 24 | 25 | @Target(ElementType.PARAMETER) 26 | @Retention(RetentionPolicy.RUNTIME) 27 | @Documented 28 | public @interface CurrentUser {} 29 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/java/com/omnissa/idm/samples/appauth/Application.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The AppAuth for Android Authors. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the 10 | * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | * express or implied. See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package com.omnissa.idm.samples.appauth; 16 | 17 | import android.support.v7.app.AppCompatDelegate; 18 | 19 | /** 20 | * Application object; ensures that the support library is correctly configured for use of 21 | * vector drawables. 22 | */ 23 | public class Application extends android.app.Application { 24 | @Override 25 | public void onCreate() { 26 | super.onCreate(); 27 | AppCompatDelegate.setCompatVectorFromResourcesEnabled(true); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/main/java/com/omnissa/idm/samples/saml/controllers/LandingController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Vincenzo De Notaris 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.omnissa.idm.samples.saml.controllers; 18 | 19 | import org.springframework.security.core.userdetails.User; 20 | import org.springframework.stereotype.Controller; 21 | import org.springframework.ui.Model; 22 | import org.springframework.web.bind.annotation.RequestMapping; 23 | 24 | import com.omnissa.idm.samples.saml.stereotypes.CurrentUser; 25 | 26 | @Controller 27 | public class LandingController { 28 | 29 | @RequestMapping("/landing") 30 | public String landing(@CurrentUser User user, Model model) { 31 | model.addAttribute("username", user.getUsername()); 32 | return "landing"; 33 | } 34 | 35 | } 36 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-oauth2-resource-server/src/test/java/com/omnissa/idm/samples/oauth2/ResourceApplicationTest.java: -------------------------------------------------------------------------------- 1 | package com.omnissa.idm.samples.oauth2; 2 | 3 | import org.junit.Test; 4 | import org.junit.runner.RunWith; 5 | import org.springframework.beans.factory.annotation.Autowired; 6 | import org.springframework.boot.test.context.SpringBootTest; 7 | import org.springframework.boot.test.web.client.TestRestTemplate; 8 | import org.springframework.test.context.junit4.SpringRunner; 9 | 10 | import static org.assertj.core.api.Assertions.assertThat; 11 | 12 | /** 13 | * Test the application configuration can load fine (integration test). 14 | */ 15 | @RunWith(SpringRunner.class) 16 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 17 | public class ResourceApplicationTest { 18 | 19 | @Autowired 20 | private TestRestTemplate restTemplate; 21 | 22 | @Test 23 | public void contextLoads() { 24 | } 25 | 26 | @Test 27 | public void canAccessHome() { 28 | String body = this.restTemplate.getForObject("/", String.class); 29 | assertThat(body).isEqualTo("Home resource (unprotected)\n"); 30 | } 31 | 32 | @Test 33 | public void cannotAccessProtectedResource() { 34 | String body = this.restTemplate.getForObject("/resource", String.class); 35 | assertThat(body).contains("{\"error\":\"unauthorized\",\"error_description\":\"Full authentication is required to access this resource\"}"); 36 | } 37 | 38 | } -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 24 5 | buildToolsVersion "24.0.2" 6 | defaultConfig { 7 | applicationId "com.omnissa.idm.samples.appauth" 8 | minSdkVersion 16 9 | targetSdkVersion 24 10 | versionCode 1 11 | versionName "1.0" 12 | testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner" 13 | 14 | vectorDrawables.useSupportLibrary = true 15 | } 16 | buildTypes { 17 | release { 18 | minifyEnabled false 19 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 20 | } 21 | } 22 | } 23 | 24 | dependencies { 25 | compile fileTree(dir: 'libs', include: ['*.jar']) 26 | androidTestCompile('com.android.support.test.espresso:espresso-core:2.2.2', { 27 | exclude group: 'com.android.support', module: 'support-annotations' 28 | }) 29 | compile 'com.android.support:appcompat-v7:24.0.0' 30 | compile "com.android.support:design:24.0.0" 31 | compile 'com.github.bumptech.glide:glide:3.7.0' 32 | compile 'net.openid:appauth:0.3.0' 33 | 34 | testCompile 'junit:junit:4.12' 35 | testCompile 'org.robolectric:robolectric:3.1' 36 | testCompile 'com.squareup.assertj:assertj-android:1.1.1', { 37 | exclude group: 'com.android.support', module: 'support-annotations' 38 | } 39 | testCompile 'org.mockito:mockito-core:1.10.19' 40 | } 41 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-oauth2-resource-server/src/main/java/com/omnissa/idm/samples/oauth2/ResourceApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.omnissa.idm.samples.oauth2; 17 | 18 | import org.springframework.boot.SpringApplication; 19 | import org.springframework.boot.autoconfigure.SpringBootApplication; 20 | import org.springframework.web.bind.annotation.RequestMapping; 21 | import org.springframework.web.bind.annotation.RestController; 22 | 23 | import java.security.Principal; 24 | 25 | @SpringBootApplication 26 | @RestController 27 | class ResourceApplication { 28 | 29 | @RequestMapping("/") 30 | public String home() { 31 | return "Home resource (unprotected)\n"; 32 | } 33 | 34 | @RequestMapping("/resource") 35 | public String protectedResource(Principal principal) { 36 | return "Resource granted to " + principal.getName() + "!\n"; 37 | } 38 | 39 | public static void main(String[] args) { 40 | SpringApplication.run(ResourceApplication.class, args); 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/values/idp_configs_optional.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 7 | 8 | 9 | 10 | Omnissa 11 | 12 | 13 | SAAS/auth/oauthtoken 14 | SAAS/auth/oauth2/authorize 15 | 16 | 17 | SAAS/auth/device/register 18 | 19 | SAAS/API/1.0/REST/oauth2/activate 20 | 21 | 22 | openid profile email user 23 | SAAS/jersey/manager/api/userinfo 24 | SAAS/jersey/manager/api/scim/Me 25 | 26 | 27 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-oauth2/src/test/java/com/omnissa/idm/samples/oauth2/OmnissaPrincipalExtractorTest.java: -------------------------------------------------------------------------------- 1 | package com.omnissa.idm.samples.oauth2; 2 | 3 | import org.junit.Test; 4 | import org.springframework.boot.autoconfigure.security.oauth2.resource.PrincipalExtractor; 5 | 6 | import java.util.HashMap; 7 | import java.util.Map; 8 | 9 | import static org.junit.Assert.assertEquals; 10 | import static org.junit.Assert.assertNull; 11 | 12 | /** 13 | * Unit tests for our special extractor. 14 | */ 15 | public class OmnissaPrincipalExtractorTest { 16 | 17 | PrincipalExtractor principalExtractor = new OmnissaPrincipalExtractor(); 18 | 19 | @Test 20 | public void testExtractPrincipal() throws Exception { 21 | Map map = new HashMap<>(); 22 | map.put(OmnissaPrincipalExtractor.OMNISSA_KEY_SUBJECT, "test"); 23 | 24 | assertEquals("test", principalExtractor.extractPrincipal(map)); 25 | } 26 | 27 | @Test 28 | public void testExtractPrincipalIfMultipleFields() throws Exception { 29 | Map map = new HashMap<>(); 30 | map.put(OmnissaPrincipalExtractor.OMNISSA_KEY_SUBJECT, "test"); 31 | map.put("name", "test-other"); 32 | 33 | assertEquals("test", principalExtractor.extractPrincipal(map)); 34 | } 35 | 36 | @Test 37 | public void testExtractPrincipalReturnsNullIfEmpty() throws Exception { 38 | assertNull(principalExtractor.extractPrincipal(new HashMap<>())); 39 | } 40 | 41 | @Test 42 | public void testExtractPrincipalReturnsNullIfNotFound() throws Exception { 43 | 44 | Map map = new HashMap<>(); 45 | map.put("name", "test-other"); 46 | assertNull(principalExtractor.extractPrincipal(new HashMap<>())); 47 | } 48 | } -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | Omnissa AppAuth 3 | Authorization granted 4 | Exchange completed successfully 5 | Token refresh failed 6 | Exchanging code for token 7 | OpenID AppAuth Demo 8 | OpenID Foundation Logo 9 | Refresh token 10 | Access token expires at: %s 11 | No access token returned 12 | No refresh token returned 13 | Refresh token returned 14 | No ID token returned 15 | ID token returned 16 | View user info 17 | View user info (SCIM) 18 | unknown 19 | Sign in with: 20 | No IDPs are configured. Please edit idp_configs.xml 21 | Authorization failed 22 | User profile picture 23 | SCIM User Information: 24 | Exchanging activation code 25 | Device activation failed 26 | 27 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-oauth2/src/test/java/com/omnissa/idm/samples/oauth2/SocialApplicationTests.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2015 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.omnissa.idm.samples.oauth2; 17 | 18 | import org.junit.Before; 19 | import org.junit.Test; 20 | import org.junit.runner.RunWith; 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties; 23 | import org.springframework.boot.test.context.SpringBootTest; 24 | import org.springframework.boot.test.mock.mockito.MockBean; 25 | import org.springframework.boot.test.web.client.TestRestTemplate; 26 | import org.springframework.security.core.token.TokenService; 27 | import org.springframework.test.context.junit4.SpringRunner; 28 | 29 | import java.util.Map; 30 | 31 | import static org.assertj.core.api.Assertions.assertThat; 32 | import static org.mockito.Mockito.verify; 33 | import static org.mockito.Mockito.when; 34 | 35 | 36 | @RunWith(SpringRunner.class) 37 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 38 | public class SocialApplicationTests { 39 | 40 | @Autowired 41 | private TestRestTemplate restTemplate; 42 | 43 | @Test 44 | public void contextLoads() { 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | # Contributing to Omnissa idm 2 | 3 | The Omnissa idm project team welcomes contributions from the community. 4 | 5 | ## Contribution Flow 6 | 7 | This is a rough outline of what a contributor's workflow looks like: 8 | 9 | - Fork the repository 10 | - Create a topic branch on *your fork*\* from where you want to base your work 11 | - Make commits of logical units 12 | - Make sure your commit messages are in the proper format (see below) 13 | - Push your changes to a topic branch in your fork of the repository 14 | - Submit a pull request 15 | 16 | \* Make sure that you create a branch on your fork and not the main repository. 17 | If you push your changes together with your PR from a branch you created on the main repository, it would 18 | trigger the CI twice (on push and on PR), resulting in unecessary load on Github Actions. 19 | 20 | Example: 21 | 22 | ``` shell 23 | git remote add upstream https://github.com/omnissa-archive/idm.git 24 | git checkout -b my-new-feature master 25 | git commit -a 26 | git push origin my-new-feature 27 | ``` 28 | 29 | ### Staying In Sync With Upstream 30 | 31 | When your branch gets out of sync with the omnissa-archive/master branch, use the following to update: 32 | 33 | ``` shell 34 | git checkout my-new-feature 35 | git fetch -a 36 | git pull --rebase upstream master 37 | git push --force-with-lease origin my-new-feature 38 | ``` 39 | 40 | ### Formatting Commit Messages 41 | 42 | We follow the conventions on [How to Write a Git Commit Message](http://chris.beams.io/posts/git-commit/). 43 | 44 | Be sure to include any related GitHub issue references in the commit message. See 45 | [GFM syntax](https://guides.github.com/features/mastering-markdown/#GitHub-flavored-markdown) for referencing issues 46 | and commits. 47 | 48 | ## Reporting Bugs and Creating Issues 49 | 50 | When opening a new issue, try to roughly follow the commit message format conventions above. 51 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/main/java/com/omnissa/idm/samples/saml/config/MvcConfig.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Vincenzo De Notaris 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.omnissa.idm.samples.saml.config; 18 | 19 | import java.util.List; 20 | 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.context.annotation.Configuration; 23 | import org.springframework.web.method.support.HandlerMethodArgumentResolver; 24 | import org.springframework.web.servlet.config.annotation.ViewControllerRegistry; 25 | import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter; 26 | 27 | import com.omnissa.idm.samples.saml.core.CurrentUserHandlerMethodArgumentResolver; 28 | 29 | @Configuration 30 | public class MvcConfig extends WebMvcConfigurerAdapter { 31 | 32 | @Autowired 33 | CurrentUserHandlerMethodArgumentResolver currentUserHandlerMethodArgumentResolver; 34 | 35 | @Override 36 | public void addViewControllers(ViewControllerRegistry registry) { 37 | registry.addViewController("/").setViewName("index"); 38 | registry.addViewController("/error").setViewName("error"); 39 | } 40 | 41 | @Override 42 | public void addArgumentResolvers(List argumentResolvers){ 43 | argumentResolvers.add(currentUserHandlerMethodArgumentResolver); 44 | } 45 | 46 | } -------------------------------------------------------------------------------- /samples/webapp-spring-boot-oauth2/src/main/resources/static/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Demo 7 | 8 | 9 | 10 | 12 | 13 | 15 | 16 | 17 |

Login

18 |
19 |
20 | With WorkspaceONE: click here 21 |
22 |
23 |
24 | Logged in as: 25 |
26 | 27 |
28 |
29 | 30 | 61 | 62 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/main/java/com/omnissa/idm/samples/saml/core/CurrentUserHandlerMethodArgumentResolver.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Vincenzo De Notaris 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.omnissa.idm.samples.saml.core; 18 | 19 | import java.security.Principal; 20 | 21 | import org.springframework.core.MethodParameter; 22 | import org.springframework.security.core.Authentication; 23 | import org.springframework.security.core.userdetails.User; 24 | import org.springframework.stereotype.Component; 25 | import org.springframework.web.bind.support.WebArgumentResolver; 26 | import org.springframework.web.bind.support.WebDataBinderFactory; 27 | import org.springframework.web.context.request.NativeWebRequest; 28 | import org.springframework.web.method.support.HandlerMethodArgumentResolver; 29 | import org.springframework.web.method.support.ModelAndViewContainer; 30 | 31 | import com.omnissa.idm.samples.saml.stereotypes.CurrentUser; 32 | 33 | @Component 34 | public class CurrentUserHandlerMethodArgumentResolver implements 35 | HandlerMethodArgumentResolver { 36 | 37 | public boolean supportsParameter(MethodParameter methodParameter) { 38 | return methodParameter.getParameterAnnotation(CurrentUser.class) != null 39 | && methodParameter.getParameterType().equals(User.class); 40 | } 41 | 42 | public Object resolveArgument(MethodParameter methodParameter, 43 | ModelAndViewContainer mavContainer, NativeWebRequest webRequest, 44 | WebDataBinderFactory binderFactory) throws Exception { 45 | if (this.supportsParameter(methodParameter)) { 46 | Principal principal = (Principal) webRequest.getUserPrincipal(); 47 | return (User) ((Authentication) principal).getPrincipal(); 48 | } else { 49 | return WebArgumentResolver.UNRESOLVED; 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/test/java/net/openid/appauth/OmnissaAppAuthTest.java: -------------------------------------------------------------------------------- 1 | package net.openid.appauth; 2 | 3 | import android.net.Uri; 4 | 5 | /** 6 | * Common class to hold test values. 7 | */ 8 | public class OmnissaAppAuthTest { 9 | 10 | public static final Uri TEST_IDP_TOKEN_ENDPOINT = 11 | Uri.parse("https://testidp.example.com/authorize"); 12 | public static final Uri TEST_IDP_AUTH_ENDPOINT = Uri.parse("https://testidp.example.com/token"); 13 | public static final Uri TEST_IDP_ACTIVATION_ENDPOINT = 14 | Uri.parse("https://testidp.example.com/activate"); 15 | public static final Uri TEST_IDP_REGISTRATION_ENDPOINT = 16 | Uri.parse("https://testidp.example.com/register"); 17 | 18 | public static final String TEST_ACTIVATION_CODE = "activation-code"; 19 | public static final String TEST_AUTHORIZATION_CODE = "authorization-code"; 20 | 21 | public static final Uri TEST_APP_REDIRECT_URI = Uri.parse("test://my-redirect-uri"); 22 | public static final String TEST_APP_SCHEME = "test"; 23 | 24 | public static final String TEST_DEVICE_NAME = "device name"; 25 | public static final String TEST_USER_DEVICE_JSON = "{ \"info\" : \"user_device\" }"; 26 | public static final String TEST_APP_TEMPLATE = "app_template"; 27 | public static final String TEST_SCOPE = "scope"; 28 | public static final String TEST_STATE = "state"; 29 | public static final String TEST_CLIENT_ID = "client_id"; 30 | public static final String TEST_CLIENT_SECRET = "the_client_secret"; 31 | 32 | 33 | public static AuthorizationServiceConfiguration getTestServiceConfig() { 34 | return new AuthorizationServiceConfiguration( 35 | TEST_IDP_AUTH_ENDPOINT, 36 | TEST_IDP_TOKEN_ENDPOINT, 37 | TEST_IDP_REGISTRATION_ENDPOINT); 38 | } 39 | 40 | public static DeviceActivationRequest getTestDeviceActivationRequest() { 41 | return new DeviceActivationRequest.Builder(TEST_IDP_ACTIVATION_ENDPOINT, 42 | getTestServiceConfig(), TEST_ACTIVATION_CODE).build(); 43 | 44 | } 45 | 46 | public static DeviceRegistrationRequest.Builder getTestDeviceRegistrationRequestBuilder() { 47 | return new DeviceRegistrationRequest.Builder(getTestServiceConfig(), TEST_APP_REDIRECT_URI, 48 | TEST_DEVICE_NAME, TEST_USER_DEVICE_JSON, TEST_APP_TEMPLATE, 49 | TEST_IDP_ACTIVATION_ENDPOINT).setState(TEST_STATE); 50 | 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Omnissa Identity Manager 2 | 3 | Identity Manager is an Identity as a Service (IDaaS) offering, providing application provisioning, self-service catalog, conditional access controls and Single Sign-On (SSO) for SaaS, web, cloud and native mobile applications. 4 | 5 | ## Overview 6 | 7 | If you don't know where to start, read the introduction on existing protocols to achieve Single-Sign On with your application: 8 | 9 | * [Choosing the right authentication protocol](https://github.com/omnissa-archive/idm/wiki/Choosing-The-Right-Auth) 10 | 11 | ## How-To Guides 12 | 13 | The wiki contains a lot of documentation to help you achieve your task. Whether you want to have end-users login to your web application or mobile application, or have your service be able to call Omnissa Identity Manager API, read through the following guides: 14 | 15 | * [Integrating your web app with OAuth2.0 (end users log in)](https://github.com/omnissa-archive/idm/wiki/Integrating-Webapp-with-OAuth2) 16 | * [Integrating your mobile app with OAuth2.0 (end users log in)](https://github.com/omnissa-archive/idm/wiki/Single-sign-on-for-Mobile) 17 | * [Integrating your backend app with OAuth2.0 (service to service)](https://github.com/omnissa-archive/idm/wiki/Integrating-Client-Credentials-app-with-OAuth2) 18 | * [Validate the tokens](https://github.com/omnissa-archive/idm/wiki/Validating-Access-or-ID-Token) 19 | * [Managing Users and Groups using SCIM API](https://github.com/omnissa-archive/idm/wiki/SCIM-guide) 20 | 21 | 22 | ## Samples 23 | [![Build Status](https://travis-ci.org/omnissa/idm.svg?branch=master)](https://travis-ci.org/omnissa/idm/) 24 | Sample applications are provided - as is - to demonstrate how to integrate your application with Omnissa Identity Manager: 25 | 26 | * [Android application using the AppAuth library](https://github.com/omnissa-archive/idm/tree/master/samples/DynamicRegistrationAppAuthDemo-Android) 27 | * [SpringBoot web application using OAuth2.0](https://github.com/omnissa-archive/idm/tree/master/samples/webapp-spring-boot-oauth2) 28 | * [SpringBoot web application acting as a resource server using OAuth2.0](https://github.com/omnissa-archive/idm/tree/master/samples/webapp-spring-boot-oauth2-resource-server) 29 | * [SpringBoot web application using SAML2](https://github.com/omnissa-archive/idm/tree/master/samples/webapp-spring-boot-saml2) 30 | 31 | ## Resources 32 | * [Reference API File](https://github.com/omnissa-archive/idm/blob/master/apidocs/swagger.json) 33 | * [Identity Manager API Documentation](https://omnissa-archive.github.io/idm/api-docs) 34 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/main/java/com/omnissa/idm/samples/saml/core/SAMLUserDetailsServiceImpl.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Vincenzo De Notaris 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.omnissa.idm.samples.saml.core; 18 | 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | import org.springframework.security.core.GrantedAuthority; 22 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 23 | import org.springframework.security.core.userdetails.User; 24 | import org.springframework.security.core.userdetails.UsernameNotFoundException; 25 | import org.springframework.security.saml.SAMLCredential; 26 | import org.springframework.security.saml.userdetails.SAMLUserDetailsService; 27 | import org.springframework.stereotype.Service; 28 | 29 | import java.util.ArrayList; 30 | import java.util.List; 31 | 32 | @Service 33 | public class SAMLUserDetailsServiceImpl implements SAMLUserDetailsService { 34 | 35 | // Logger 36 | private static final Logger LOG = LoggerFactory.getLogger(SAMLUserDetailsServiceImpl.class); 37 | 38 | public Object loadUserBySAML(SAMLCredential credential) 39 | throws UsernameNotFoundException { 40 | 41 | // The method is supposed to identify local account of user referenced by 42 | // data in the SAML assertion and return UserDetails object describing the user. 43 | 44 | String userID = credential.getNameID().getValue(); 45 | 46 | LOG.info(userID + " is logged in"); 47 | List authorities = new ArrayList(); 48 | GrantedAuthority authority = new SimpleGrantedAuthority("ROLE_USER"); 49 | authorities.add(authority); 50 | 51 | // In a real scenario, this implementation has to locate user in a arbitrary 52 | // dataStore based on information present in the SAMLCredential and 53 | // returns such a date in a form of application specific UserDetails object. 54 | return new User(userID, "", true, true, true, true, authorities); 55 | } 56 | 57 | } 58 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/test/java/net/openid/appauth/DeviceActivationResponseTest.java: -------------------------------------------------------------------------------- 1 | package net.openid.appauth; 2 | 3 | import org.json.JSONObject; 4 | import org.junit.Before; 5 | import org.junit.Test; 6 | import org.junit.experimental.runners.Enclosed; 7 | import org.junit.runner.RunWith; 8 | import org.robolectric.RobolectricTestRunner; 9 | import org.robolectric.annotation.Config; 10 | 11 | import static net.openid.appauth.DeviceActivationResponse.PARAM_CLIENT_ID; 12 | import static net.openid.appauth.DeviceActivationResponse.PARAM_CLIENT_SECRET; 13 | import static org.assertj.core.api.Assertions.assertThat; 14 | 15 | /** 16 | * Unit test for the @{link DeviceActivationResponse} class. 17 | */ 18 | @RunWith(RobolectricTestRunner.class) 19 | @Config(constants = com.omnissa.idm.samples.appauth.BuildConfig.class, sdk = 16) 20 | public class DeviceActivationResponseTest extends OmnissaAppAuthTest { 21 | 22 | private static final Object TEST_CLIENT_ID = "client_id"; 23 | private static final Object TEST_CLIENT_SECRET = "client_secret"; 24 | 25 | private static final String TEST_JSON = "{\n" 26 | + " \"client_id\": \"" + TEST_CLIENT_ID + "\"}"; 27 | 28 | private DeviceActivationResponse.Builder mMinimalBuilder; 29 | private JSONObject mJson; 30 | 31 | @Before 32 | public void setUp() throws Exception { 33 | mJson = new JSONObject(TEST_JSON); 34 | mMinimalBuilder = 35 | new DeviceActivationResponse.Builder(getTestDeviceActivationRequest()); 36 | } 37 | 38 | @Test(expected = IllegalArgumentException.class) 39 | public void testBuilderSetEmptyClientId() { 40 | mMinimalBuilder.setClientId(""); 41 | } 42 | 43 | @Test 44 | public void testFromJson() throws Exception { 45 | DeviceActivationResponse response = 46 | new DeviceActivationResponse.Builder(getTestDeviceActivationRequest()) 47 | .fromResponseJson(mJson).build(); 48 | assertThat(response.clientId).isEqualTo(TEST_CLIENT_ID); 49 | } 50 | 51 | @Test 52 | public void testFromJsonWithClientSecret() throws Exception { 53 | mJson.put(PARAM_CLIENT_SECRET, TEST_CLIENT_SECRET); 54 | DeviceActivationResponse response = 55 | new DeviceActivationResponse.Builder(getTestDeviceActivationRequest()) 56 | .fromResponseJson(mJson).build(); 57 | 58 | assertThat(response.clientId).isEqualTo(TEST_CLIENT_ID); 59 | assertThat(response.clientSecret).isEqualTo(TEST_CLIENT_SECRET); 60 | } 61 | 62 | 63 | } -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 14 | 16 | 17 | 18 | 19 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 58 | 59 | 60 | 61 | 62 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/main/java/com/omnissa/idm/samples/saml/controllers/SSOController.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Vincenzo De Notaris 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.omnissa.idm.samples.saml.controllers; 18 | 19 | import org.slf4j.Logger; 20 | import org.slf4j.LoggerFactory; 21 | import org.springframework.beans.factory.annotation.Autowired; 22 | import org.springframework.security.authentication.AnonymousAuthenticationToken; 23 | import org.springframework.security.core.context.SecurityContextHolder; 24 | import org.springframework.security.saml.metadata.MetadataManager; 25 | import org.springframework.stereotype.Controller; 26 | import org.springframework.ui.Model; 27 | import org.springframework.web.bind.annotation.RequestMapping; 28 | import org.springframework.web.bind.annotation.RequestMethod; 29 | 30 | import javax.servlet.http.HttpServletRequest; 31 | import java.util.Set; 32 | 33 | @Controller 34 | @RequestMapping("/saml") 35 | public class SSOController { 36 | 37 | // Logger 38 | private static final Logger LOG = LoggerFactory 39 | .getLogger(SSOController.class); 40 | 41 | @Autowired 42 | private MetadataManager metadata; 43 | 44 | @RequestMapping(value = "/idpSelection", method = RequestMethod.GET) 45 | public String idpSelection(HttpServletRequest request, Model model) { 46 | if (!(SecurityContextHolder.getContext().getAuthentication() instanceof AnonymousAuthenticationToken)) { 47 | LOG.warn("The current user is already logged."); 48 | return "redirect:/landing"; 49 | } else { 50 | if (isForwarded(request)) { 51 | Set idps = metadata.getIDPEntityNames(); 52 | for (String idp : idps) 53 | LOG.info("Configured Identity Provider for SSO: " + idp); 54 | model.addAttribute("idps", idps); 55 | return "saml/idpselection"; 56 | } else { 57 | LOG.warn("Direct accesses to '/idpSelection' route are not allowed"); 58 | return "redirect:/"; 59 | } 60 | } 61 | } 62 | 63 | /* 64 | * Checks if an HTTP request has been forwarded by a servlet. 65 | */ 66 | private boolean isForwarded(HttpServletRequest request){ 67 | if (request.getAttribute("javax.servlet.forward.request_uri") == null) 68 | return false; 69 | else 70 | return true; 71 | } 72 | 73 | } 74 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-oauth2-resource-server/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.omnissa.idm.samples 7 | webapp-spring-boot-oauth2-resource-server 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | webapp-spring-boot-oauth2-resource-server 12 | Demo project for Spring Boot and Omnissa OAuth2 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 1.4.0.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | 1.8 24 | 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-actuator 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-security 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-web 38 | 39 | 40 | org.springframework.security.oauth 41 | spring-security-oauth2 42 | 43 | 44 | org.springframework.security 45 | spring-security-jwt 46 | 1.0.5.RELEASE 47 | 48 | 49 | org.springframework.boot 50 | spring-boot-starter-test 51 | test 52 | 53 | 54 | org.springframework.boot 55 | spring-boot-configuration-processor 56 | true 57 | 58 | 59 | 60 | 61 | 62 | 63 | org.springframework.boot 64 | spring-boot-maven-plugin 65 | 66 | 67 | 68 | 69 | 70 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-oauth2/README.md: -------------------------------------------------------------------------------- 1 | Log in with Omnissa Identity Manager 2 | ========================================= 3 | 4 | This demo application shows the use of Spring Boot and its built-in OAuth2 capabilities to 5 | let a user authenticate with Omnissa Identity Manager™ and then use the access token to 6 | access Omnissa Identity Manager resources (like the user information). 7 | 8 | This application is based on the [Spring Demo application](https://spring.io/guides/tutorials/spring-boot-oauth2/#_social_login_github) 9 | and has been modified to integrate Omnissa Identity Manager as an authorization server. 10 | 11 | ## Building the project 12 | 13 | ### Prerequisites 14 | 15 | - You need a [Omnissa Identity Manager organization](http://www.air-watch.com/omnissa-identity-manager-free-trial), like https://dev.omnissaidentity.asia, where you have __admin__ access. 16 | - The project requires JDK 8 17 | 18 | ### Building from IDE 19 | 20 | * Clone this project. 21 | * Then import the root folder. You can run the main class `SocialApplication`. 22 | 23 | ### Building from the Command line 24 | 25 | You can run the app by using: 26 | `$ mvn spring-boot:run` 27 | 28 | or by building the jar file and running it with `mvn package` and `java -jar target/*.jar` (per the Spring Boot docs and other available documentation). 29 | 30 | ### Configure the Demo App 31 | 32 | * Create an OAuth2.0 client in the Omnissa Identity Manager admin console. 33 | Go to `Catalog` -> `Settings` -> `Remote App Access`. Click on `Create Client`. 34 | The _redirect URI_ must be set to `http://localhost:8080/login/omnissa` 35 | 36 | * Edit the file `./src/main/resources/application.yml` to set your own Omnissa Identity Manager organization URL in the defined endpoints, 37 | and the OAuth2 client id and client secret as they were defined in the previous step: 38 | 39 | ```yaml 40 | omnissa: 41 | client: 42 | accessTokenUri: /SAAS/auth/oauthtoken 43 | userAuthorizationUri: /SAAS/auth/oauth2/authorize 44 | clientId: 45 | clientSecret: 46 | resource: 47 | userInfoUri: /SAAS/jersey/manager/api/userinfo 48 | ``` 49 | 50 | ### Test the application 51 | 52 | The web application will be available on `http://localhost:8080`. Click on "Login with WorkspaceONE" to start the OAuth2 flow. 53 | You can use the default values and log in to the demo Omnissa Identity Manager system using: 54 | 55 | * Username: `userN`, where N=1..10 56 | * Password: `omnissa` 57 | 58 | ### What is happening? 59 | 60 | Your web application is a client application that authenticates the users using Omnissa Identity Manager 61 | through the OAuth2 authorization code grant and obtains an access token that is used to fetch some more information 62 | about the user. In that case, Omnissa Identity Manager is the authorization and resource server and check the access token before returning 63 | the user's information. 64 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/java/net/openid/appauth/DeviceRegistrationPendingIntentStore.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The AppAuth for Android Authors. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the 10 | * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | * express or implied. See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package net.openid.appauth; 16 | 17 | import android.app.PendingIntent; 18 | import android.support.annotation.VisibleForTesting; 19 | import android.support.customtabs.CustomTabsIntent; 20 | 21 | import java.util.HashMap; 22 | import java.util.Map; 23 | 24 | /** 25 | * Singleton to mimic PendingIntentStore to store our {@link net.openid.appauth.DeviceRegistrationRequest} 26 | *

27 | * Stores {@link android.app.PendingIntent} associated with each {@link DeviceRegistrationRequest} made via 28 | * {@link DeviceAuthorizationService#performDeviceRegistrationRequest(DeviceRegistrationRequest, PendingIntent, CustomTabsIntent)}. 29 | * The pending intents are read and sent by 30 | * the {@link RedirectUriRegistrationReceiverActivity} when the redirect Uri is received. 31 | */ 32 | class DeviceRegistrationPendingIntentStore { 33 | private Map mRequests = new HashMap<>(); 34 | private Map mPendingIntents = new HashMap<>(); 35 | 36 | private static DeviceRegistrationPendingIntentStore sInstance; 37 | 38 | private DeviceRegistrationPendingIntentStore() { 39 | } 40 | 41 | public static synchronized DeviceRegistrationPendingIntentStore getInstance() { 42 | if (sInstance == null) { 43 | sInstance = new DeviceRegistrationPendingIntentStore(); 44 | } 45 | return sInstance; 46 | } 47 | 48 | public void addPendingIntent(DeviceRegistrationRequest request, PendingIntent intent) { 49 | Logger.verbose("Adding pending intent for state %s", request.state); 50 | mRequests.put(request.state, request); 51 | mPendingIntents.put(request.state, intent); 52 | } 53 | 54 | public DeviceRegistrationRequest getOriginalRequest(String state) { 55 | Logger.verbose("Retrieving original request for state %s", state); 56 | return mRequests.remove(state); 57 | } 58 | 59 | public PendingIntent getPendingIntent(String state) { 60 | Logger.verbose("Retrieving pending intent for scheme %s", state); 61 | return mPendingIntents.remove(state); 62 | } 63 | 64 | @VisibleForTesting 65 | void clearAll() { 66 | mPendingIntents.clear(); 67 | mRequests.clear(); 68 | } 69 | } 70 | 71 | 72 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/README.md: -------------------------------------------------------------------------------- 1 | # Mobile SSO Sample Application For Android 2 | 3 | ## Overview 4 | 5 | This application is an Android native demo application to show you how to achieve mobile single sign-on using the [AppAuth library](https://github.com/openid/AppAuth-Android) with Omnissa Identity Manager as your Authorization Server. 6 | It is based on the [demo application](https://github.com/openid/AppAuth-Android) provided by the OpenID Foundation. 7 | 8 | Omnissa Identity Manager supports the OAuth2.0 Authorization Code Grant for mobile apps but requires each application instance to register a unique __Client ID__ and __Client Secret__ for additional security. 9 | This application shows how to set up mobile single sign-on using the AppAuth standard library. 10 | 11 | ## Building the project 12 | 13 | ### Prerequisites 14 | 15 | - You need a [Omnissa Identity Manager organization](http://www.air-watch.com/omnissa-identity-manager-free-trial), like https://dev.omnissaidentity.asia, where you have __admin__ access. 16 | - The project requires the Android SDK for API level 23 (Marshmallow) to build, though the produced binaries only require API level 16 (Jellybean) to be used. 17 | 18 | ### Building from Android Studio 19 | 20 | * Clone this project. 21 | * Then in AndroidStudio, use File -> New -> Import project. Select the root folder. 22 | 23 | ### Building from the Command line 24 | 25 | DynamicRegistrationAppAuthDemo for Android uses Gradle as its build system. In order to build the library and app binaries, run `./gradlew assemble` 26 | The demo app is output to _app/build/outputs/apk_. In order to run the tests and code analysis, run `./gradlew check`. 27 | 28 | ### Configure the Demo App 29 | 30 | You will need to edit the file `./app/src/main/res/values/idp_configs.xml` and edit the following values: 31 | 32 | * the organization URL: this is the full URL of your Omnissa Identity Manager organization: 33 | 34 | ```xml 35 | 36 | https://dev.omnissaidentity.asia 37 | ``` 38 | 39 | * the application template and redirection URI: this is the template you defined in the Omnissa Identity Manager admin console under 40 | `Catalog` -> `Settings` -> `Remote App Access`. Click on `Templates` and then `Create Template`. 41 | The `omnissa_auth_redirect_scheme` and `omnissa_auth_redirect_uri` must match what you defined in the previous application template. 42 | 43 | ```xml 44 | 45 | Omnissa-AppAuth-Samples-Template 46 | com.omnissa.idm.samples.mobilesso 47 | com.omnissa.idm.samples.mobilesso://oauth2redirect 48 | ``` 49 | 50 | ### Test the application 51 | 52 | You can use the default values and log in to the demo Omnissa Identity Manager system using: 53 | 54 | * Username: `userN`, where N=1..10 55 | * Password: `omnissa` 56 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-oauth2/pom.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 4.0.0 5 | 6 | com.omnissa.idm.samples 7 | webapp-spring-boot-oauth2 8 | 0.0.1-SNAPSHOT 9 | jar 10 | 11 | webapp-spring-boot-oauth2 12 | Demo project for Spring Boot and Omnissa OAuth2 13 | 14 | 15 | org.springframework.boot 16 | spring-boot-starter-parent 17 | 1.4.0.RELEASE 18 | 19 | 20 | 21 | 22 | UTF-8 23 | 1.8 24 | 25 | 26 | 27 | 28 | org.springframework.boot 29 | spring-boot-starter-actuator 30 | 31 | 32 | org.springframework.boot 33 | spring-boot-starter-security 34 | 35 | 36 | org.springframework.boot 37 | spring-boot-starter-web 38 | 39 | 40 | org.springframework.security.oauth 41 | spring-security-oauth2 42 | 43 | 44 | org.webjars 45 | angularjs 46 | 1.4.3 47 | 48 | 49 | org.webjars 50 | jquery 51 | 2.1.1 52 | 53 | 54 | org.webjars 55 | bootstrap 56 | 3.2.0 57 | 58 | 59 | org.webjars 60 | webjars-locator 61 | 62 | 63 | 64 | org.springframework.boot 65 | spring-boot-starter-test 66 | test 67 | 68 | 69 | org.springframework.boot 70 | spring-boot-configuration-processor 71 | true 72 | 73 | 74 | 75 | 76 | 77 | 78 | org.springframework.boot 79 | spring-boot-maven-plugin 80 | 81 | 82 | 83 | 84 | 85 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/test/java/com/omnissa/idm/samples/saml/core/SAMLUserDetailsServiceImplTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Vincenzo De Notaris 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.omnissa.idm.samples.saml.core; 18 | 19 | import com.omnissa.idm.samples.saml.CommonTestSupport; 20 | import org.junit.Test; 21 | import org.junit.runner.RunWith; 22 | import org.opensaml.saml2.core.NameID; 23 | import org.springframework.beans.factory.annotation.Autowired; 24 | import org.springframework.boot.test.context.SpringBootTest; 25 | import org.springframework.security.core.GrantedAuthority; 26 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 27 | import org.springframework.security.core.userdetails.User; 28 | import org.springframework.security.saml.SAMLCredential; 29 | import org.springframework.test.context.junit4.SpringRunner; 30 | 31 | import java.util.ArrayList; 32 | import java.util.List; 33 | 34 | import static org.junit.Assert.assertEquals; 35 | import static org.junit.Assert.assertNotNull; 36 | import static org.junit.Assert.assertTrue; 37 | import static org.mockito.Mockito.mock; 38 | import static org.mockito.Mockito.when; 39 | 40 | 41 | @RunWith(SpringRunner.class) 42 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 43 | public class SAMLUserDetailsServiceImplTest extends CommonTestSupport { 44 | 45 | @Autowired 46 | private SAMLUserDetailsServiceImpl userDetailsService; 47 | 48 | @Test 49 | public void testLoadUserBySAML() { 50 | // given 51 | NameID mockNameID = mock(NameID.class); 52 | when(mockNameID.getValue()).thenReturn(USER_NAME); 53 | 54 | SAMLCredential credentialsMock = mock(SAMLCredential.class); 55 | when(credentialsMock.getNameID()).thenReturn(mockNameID); 56 | 57 | // when 58 | Object actual = userDetailsService.loadUserBySAML(credentialsMock); 59 | 60 | // / then 61 | assertNotNull(actual); 62 | assertTrue(actual instanceof User); 63 | 64 | User user = (User) actual; 65 | assertEquals(USER_NAME, user.getUsername()); 66 | assertEquals(USER_PASSWORD, user.getPassword()); 67 | assertTrue(user.isEnabled()); 68 | assertTrue(user.isAccountNonExpired()); 69 | assertTrue(user.isCredentialsNonExpired()); 70 | assertTrue(user.isAccountNonLocked()); 71 | assertEquals(1, user.getAuthorities().size()); 72 | 73 | List authorities = new ArrayList<>(user.getAuthorities()); 74 | Object authority = authorities.get(0); 75 | 76 | assertTrue(authority instanceof SimpleGrantedAuthority); 77 | assertEquals(USER_ROLE, ((SimpleGrantedAuthority) authority).getAuthority()); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/java/net/openid/appauth/RedirectUriRegistrationReceiverActivity.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The AppAuth for Android Authors. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the 10 | * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | * express or implied. See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package net.openid.appauth; 16 | 17 | import android.annotation.SuppressLint; 18 | import android.app.Activity; 19 | import android.app.PendingIntent; 20 | import android.content.Intent; 21 | import android.net.Uri; 22 | import android.os.Bundle; 23 | import android.support.annotation.VisibleForTesting; 24 | 25 | /** 26 | * Activity that receives the redirect Uri sent by the device registration endpoint. This activity gets launched 27 | * when the user approves the app for use and it starts the {@link PendingIntent} given in 28 | * {@link DeviceAuthorizationService#performDeviceRegistrationRequest}. 29 | *

30 | *

App developers using this code must to register this activity in the manifest 31 | * with one intent filter for each redirect URI they are intending to use. 32 | *

33 | *

34 |  * {@code
35 |  * < intent-filter>
36 |  *   < action android:name="android.intent.action.VIEW"/>
37 |  *   < category android:name="android.intent.category.DEFAULT"/>
38 |  *   < category android:name="android.intent.category.BROWSABLE"/>
39 |  *   < data android:scheme="REDIRECT_URI_SCHEME"/>
40 |  * < /intent-filter>
41 |  * }
42 |  * 
43 | */ 44 | @SuppressLint("Registered") 45 | public class RedirectUriRegistrationReceiverActivity extends Activity { 46 | 47 | private static final String KEY_STATE = "state"; 48 | 49 | @Override 50 | public void onCreate(Bundle savedInstanceBundle) { 51 | super.onCreate(savedInstanceBundle); 52 | Intent intent = getIntent(); 53 | Uri data = intent.getData(); 54 | String state = data.getQueryParameter(KEY_STATE); 55 | DeviceRegistrationRequest request = 56 | DeviceRegistrationPendingIntentStore.getInstance().getOriginalRequest(state); 57 | PendingIntent target = 58 | DeviceRegistrationPendingIntentStore.getInstance().getPendingIntent(state); 59 | 60 | if (request == null) { 61 | Logger.error("Response received for unknown device registration request with state %s", 62 | state); 63 | finish(); 64 | return; 65 | } 66 | 67 | DeviceRegistrationResponse response = DeviceRegistrationResponse.fromUri(request, data); 68 | Intent responseData = response.toIntent(); 69 | 70 | Logger.debug("Forwarding redirect, data=" + data.toString()); 71 | try { 72 | target.send(this, 0, responseData); 73 | } catch (PendingIntent.CanceledException e) { 74 | Logger.errorWithStack(e, "Unable to send pending intent"); 75 | } 76 | 77 | finish(); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/README.md: -------------------------------------------------------------------------------- 1 | Log in with Omnissa Identity Manager 2 | =================================== 3 | 4 | This demo application shows how to use Spring Boot and the Spring 5 | security SAML2 extensions to let a user authenticate with Omnissa 6 | Identity Manager™, using the SAML2 protocol. 7 | 8 | This application is based on the [Spring SAML2 Demo application](https://github.com/vdenotaris/spring-boot-security-saml-sample) 9 | and has been modified to integrate Omnissa Identity Manager as an identity provider (IdP). 10 | 11 | Building the project 12 | -------------------- 13 | 14 | ### Prerequisites 15 | 16 | - You need a [Omnissa Identity Manager](http://www.air-watch.com/omnissa-identity-manager-free-trial) 17 | tenant, like https://dev.omnissaidentity.asia, where you have 18 | **admin** access (if you want to add your own application). You can 19 | test the application as is, as it is configured by default on an 20 | provided tenant. 21 | 22 | - The project requires JDK 8. 23 | 24 | ### Building from IDE 25 | 26 | - Clone this project. 27 | 28 | - Then import the root folder. You can run the main class named 29 | `com.omnissa.idm.samples.saml.Application`. 30 | 31 | ### Building from the Command Line 32 | 33 | You can run the application locally by using 34 | 35 | - `$ ./gradlew bootRun` 36 | 37 | - Navigate to `http://localhost:8080` 38 | 39 | Another option is to build the jar file and run it with 40 | `./gradlew build` and 41 | `java -jar build/libs/webapp-spring-boot-saml2.jar` (per the Spring Boot 42 | docs and other available documentation). 43 | 44 | You can now select the "SSO Login Page" and the first IdP and click 45 | `Login`. You can use `user1` as username and `omnissa` as the password. 46 | 47 | ### Configure the Demo Application 48 | 49 | If you want to configure the application to log in users from your own 50 | Omnissa Identity Manager organization, you need to add and configure that 51 | SAML2 application in your Identity Manager catalog. 52 | 53 | 1. Edit the local `./src/main/resources/application.properties` 54 | file to setup your organization URL: 55 | ```properties 56 | omnissa.url=https:// 57 | ``` 58 | and run the application: `$ ./gradlew bootRun.` 59 | 60 | 2. Login to your Omnissa Identity Manager organization (https://)) as an 61 | administrator 62 | 63 | 3. Create a new SAML2 application, by clicking on the `Catalog` tab, 64 | and `Add Application` button, then select `...create a new one.` 65 | ![Create SAML2 app](images/CreateSAML2App.png) 66 | 67 | Then edit the name, description and icon of the application. Click 68 | `Next.` 69 | ![Edit SAML2 app details](images/EditSAML2App.png) 70 | 71 | 4. In the `Application Configuration` page, select `Meta-data XML` for 72 | the `Configure Via` option. And paste the XML content that you 73 | downloaded from your running local application: 74 | http://localhost:8080/saml/metadata. 75 | Click `Save`. 76 | ![Configure SAML2 app](images/ConfigureSAML2App.png) 77 | 78 | 5. Add the entitlements to this application. You can choose 79 | `Add group entitlement` and type `ALL USERS` to entitle this 80 | application to all users in your system. 81 | 82 | You can now log in to your application from http://localhost:8080, and 83 | you can also launch your application from the Omnissa Identity Manager 84 | end user catalog. 85 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/test/java/com/omnissa/idm/samples/saml/controllers/SSOControllerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Vincenzo De Notaris 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.omnissa.idm.samples.saml.controllers; 18 | 19 | import com.omnissa.idm.samples.saml.CommonTestSupport; 20 | import org.junit.Before; 21 | import org.junit.Test; 22 | import org.mockito.InjectMocks; 23 | import org.mockito.Mock; 24 | import org.mockito.MockitoAnnotations; 25 | import org.springframework.boot.test.context.SpringBootTest; 26 | import org.springframework.security.saml.metadata.MetadataManager; 27 | import org.springframework.test.web.servlet.MockMvc; 28 | import org.springframework.web.servlet.View; 29 | 30 | import java.util.Arrays; 31 | import java.util.Collections; 32 | import java.util.HashSet; 33 | import java.util.Set; 34 | 35 | import static org.mockito.Mockito.when; 36 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 37 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; 38 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 39 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; 40 | import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; 41 | 42 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 43 | public class SSOControllerTest extends CommonTestSupport { 44 | 45 | private static final Set IDPS = 46 | Collections.unmodifiableSet( 47 | new HashSet<>(Arrays.asList("idp1", "idp2", "idp3"))); 48 | 49 | @InjectMocks 50 | SSOController ssoController; 51 | 52 | @Mock 53 | private MetadataManager metadata; 54 | 55 | @Mock 56 | private View mockView; 57 | 58 | private MockMvc mockMvc; 59 | 60 | @Before 61 | public void setUp() { 62 | MockitoAnnotations.initMocks(this); 63 | mockMvc = standaloneSetup(ssoController).setSingleView(mockView).build(); 64 | } 65 | 66 | @Test 67 | public void testIdpSelection() throws Exception { 68 | mockMvc.perform(get("/saml/idpSelection").session(mockHttpSession(false))) 69 | .andExpect(status().isOk()) 70 | .andExpect(view().name("redirect:/landing")); 71 | } 72 | 73 | @Test 74 | public void testIdpSelectionWithoutForwarding() throws Exception { 75 | mockMvc.perform(get("/saml/idpSelection").session(mockAnonymousHttpSession())) 76 | .andExpect(status().isOk()) 77 | .andExpect(view().name("redirect:/")); 78 | } 79 | 80 | @Test 81 | public void testIdpSelectionWithForwarding() throws Exception { 82 | // given 83 | when(metadata.getIDPEntityNames()).thenReturn(IDPS); 84 | 85 | // when / then 86 | mockMvc.perform(get("/saml/idpSelection").session(mockAnonymousHttpSession()) 87 | .requestAttr("javax.servlet.forward.request_uri", "http://forward.to") 88 | ) 89 | .andExpect(status().isOk()) 90 | .andExpect(model().attribute("idps", IDPS)) 91 | .andExpect(view().name("saml/idpselection")); 92 | } 93 | 94 | } 95 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/test/java/com/omnissa/idm/samples/saml/controllers/LandingControllerTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Vincenzo De Notaris 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.omnissa.idm.samples.saml.controllers; 18 | 19 | import com.omnissa.idm.samples.saml.CommonTestSupport; 20 | import org.junit.Before; 21 | import org.junit.Test; 22 | import org.mockito.InjectMocks; 23 | import org.mockito.Mock; 24 | import org.mockito.MockitoAnnotations; 25 | import org.springframework.boot.test.context.SpringBootTest; 26 | import org.springframework.core.MethodParameter; 27 | import org.springframework.security.core.userdetails.User; 28 | import org.springframework.test.web.servlet.MockMvc; 29 | import org.springframework.web.bind.support.WebDataBinderFactory; 30 | import org.springframework.web.context.request.NativeWebRequest; 31 | import org.springframework.web.method.support.HandlerMethodArgumentResolver; 32 | import org.springframework.web.method.support.ModelAndViewContainer; 33 | import org.springframework.web.servlet.View; 34 | 35 | import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; 36 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.model; 37 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; 38 | import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.view; 39 | import static org.springframework.test.web.servlet.setup.MockMvcBuilders.standaloneSetup; 40 | 41 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 42 | public class LandingControllerTest extends CommonTestSupport { 43 | 44 | @InjectMocks 45 | private LandingController landingController; 46 | 47 | @Mock 48 | private View mockView; 49 | 50 | private MockMvc mockMvc; 51 | 52 | @Before 53 | public void setUp() 54 | { 55 | MockitoAnnotations.initMocks(this); 56 | mockMvc = standaloneSetup(landingController) 57 | .setCustomArgumentResolvers(new MockArgumentResolver()) 58 | .setSingleView(mockView).build(); 59 | } 60 | 61 | @Test 62 | public void testAnonymousLanding() throws Exception { 63 | mockMvc.perform(get("/landing").session(mockHttpSession(true))) 64 | .andExpect(status().isOk()) 65 | .andExpect(model().attribute("username", USER_NAME)) 66 | .andExpect(view().name("landing")); 67 | } 68 | 69 | private static class MockArgumentResolver implements HandlerMethodArgumentResolver 70 | { 71 | @Override 72 | public boolean supportsParameter(MethodParameter methodParameter) { 73 | return methodParameter.getParameterType().equals(User.class); 74 | } 75 | 76 | @Override 77 | public Object resolveArgument(MethodParameter methodParameter, 78 | ModelAndViewContainer modelAndViewContainer, 79 | NativeWebRequest nativeWebRequest, 80 | WebDataBinderFactory webDataBinderFactory) 81 | throws Exception { 82 | return CommonTestSupport.USER_DETAILS; 83 | } 84 | } 85 | 86 | } 87 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 25 | 26 | 32 | 33 | 39 | 40 | 41 | 48 | 49 | 55 | 56 | 57 | 65 | 66 | 67 | 68 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 25 | 26 | 32 | 33 | 39 | 40 | 41 | 48 | 49 | 55 | 56 | 57 | 65 | 66 | 67 | 68 | 77 | 78 | 79 | 80 | 81 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/test/java/com/omnissa/idm/samples/saml/CommonTestSupport.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Vincenzo De Notaris 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.omnissa.idm.samples.saml; 18 | 19 | import org.springframework.mock.web.MockHttpSession; 20 | import org.springframework.security.authentication.AnonymousAuthenticationToken; 21 | import org.springframework.security.core.GrantedAuthority; 22 | import org.springframework.security.core.authority.SimpleGrantedAuthority; 23 | import org.springframework.security.core.context.SecurityContext; 24 | import org.springframework.security.core.context.SecurityContextHolder; 25 | import org.springframework.security.core.userdetails.User; 26 | import org.springframework.security.providers.ExpiringUsernameAuthenticationToken; 27 | import org.springframework.security.web.context.HttpSessionSecurityContextRepository; 28 | 29 | import java.util.Collections; 30 | import java.util.List; 31 | 32 | import static org.mockito.Mockito.mock; 33 | import static org.mockito.Mockito.when; 34 | 35 | public class CommonTestSupport { 36 | 37 | public static final String USER_NAME = "UserName"; 38 | 39 | public static final String USER_PASSWORD = ""; 40 | 41 | public static final String USER_ROLE = "ROLE_USER"; 42 | 43 | public static final String ANONYMOUS_USER_KEY = "UserKey"; 44 | 45 | public static final String ANONYMOUS_USER_PRINCIPAL = "UserPrincipal"; 46 | 47 | public static final List AUTHORITIES = 48 | Collections.singletonList(new SimpleGrantedAuthority(USER_ROLE)); 49 | 50 | public static final User USER_DETAILS = new User(USER_NAME, USER_PASSWORD, AUTHORITIES); 51 | 52 | public MockHttpSession mockHttpSession(boolean secured) { 53 | MockHttpSession mockSession = new MockHttpSession(); 54 | 55 | SecurityContext mockSecurityContext = mock(SecurityContext.class); 56 | 57 | if (secured) { 58 | ExpiringUsernameAuthenticationToken principal = 59 | new ExpiringUsernameAuthenticationToken(null, USER_DETAILS, USER_NAME, AUTHORITIES); 60 | principal.setDetails(USER_DETAILS); 61 | when(mockSecurityContext.getAuthentication()).thenReturn(principal); 62 | } 63 | 64 | SecurityContextHolder.setContext(mockSecurityContext); 65 | mockSession.setAttribute( 66 | HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, 67 | mockSecurityContext); 68 | 69 | return mockSession; 70 | } 71 | 72 | public MockHttpSession mockAnonymousHttpSession() { 73 | MockHttpSession mockSession = new MockHttpSession(); 74 | 75 | SecurityContext mockSecurityContext = mock(SecurityContext.class); 76 | 77 | AnonymousAuthenticationToken principal = 78 | new AnonymousAuthenticationToken( 79 | ANONYMOUS_USER_KEY, 80 | ANONYMOUS_USER_PRINCIPAL, 81 | AUTHORITIES); 82 | 83 | when(mockSecurityContext.getAuthentication()).thenReturn(principal); 84 | 85 | SecurityContextHolder.setContext(mockSecurityContext); 86 | mockSession.setAttribute( 87 | HttpSessionSecurityContextRepository.SPRING_SECURITY_CONTEXT_KEY, 88 | mockSecurityContext); 89 | 90 | return mockSession; 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/test/java/net/openid/appauth/DeviceActivationRequestTest.java: -------------------------------------------------------------------------------- 1 | package net.openid.appauth; 2 | 3 | import android.net.Uri; 4 | 5 | import org.json.JSONException; 6 | import org.json.JSONObject; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.robolectric.RobolectricTestRunner; 11 | import org.robolectric.annotation.Config; 12 | 13 | import static org.assertj.core.api.Assertions.assertThat; 14 | import static org.junit.Assert.*; 15 | 16 | /** 17 | * Unit tests for the activation request. 18 | */ 19 | @RunWith(RobolectricTestRunner.class) 20 | @Config(constants = com.omnissa.idm.samples.appauth.BuildConfig.class, sdk = 16) 21 | public class DeviceActivationRequestTest extends OmnissaAppAuthTest { 22 | 23 | private static final String TEST_JSON = "{\n" 24 | + " \"activation_code\": \"" + TEST_ACTIVATION_CODE + "\",\n" 25 | + " \"endpoint\": \"" + TEST_IDP_ACTIVATION_ENDPOINT + "\"\n" 26 | + "}"; 27 | private DeviceActivationRequest.Builder mRequestBuilder; 28 | 29 | private JSONObject mJson; 30 | 31 | 32 | @Before 33 | public void setUp() throws Exception { 34 | mRequestBuilder = 35 | new DeviceActivationRequest.Builder(TEST_IDP_ACTIVATION_ENDPOINT, 36 | getTestServiceConfig(), 37 | TEST_ACTIVATION_CODE); 38 | mJson = new JSONObject(TEST_JSON); 39 | } 40 | 41 | @Test 42 | public void testBuilder() { 43 | assertValues(mRequestBuilder.build()); 44 | } 45 | 46 | @Test 47 | public void jsonDeserialize() throws Exception { 48 | mJson.put(DeviceRegistrationRequest.KEY_CONFIGURATION, getTestServiceConfig().toJson()); 49 | DeviceActivationRequest request = DeviceActivationRequest.jsonDeserialize(mJson); 50 | assertThat(request.configuration.toJsonString()) 51 | .isEqualTo(getTestServiceConfig().toJsonString()); 52 | assertMaximalValuesInJson(request, mJson); 53 | } 54 | 55 | @Test 56 | public void getActivationCode() throws Exception { 57 | DeviceActivationRequest request = mRequestBuilder.build(); 58 | assertThat(request.getActivationCode()).isEqualTo(TEST_ACTIVATION_CODE); 59 | } 60 | 61 | @Test 62 | public void getActivationEndpoint() throws Exception { 63 | DeviceActivationRequest request = mRequestBuilder.build(); 64 | assertThat(request.getActivationEndpoint()).isEqualTo(TEST_IDP_ACTIVATION_ENDPOINT); 65 | } 66 | 67 | @Test 68 | public void toRegistrationRequest() throws Exception { 69 | DeviceActivationRequest request = mRequestBuilder.build(); 70 | RegistrationRequest registrationRequest = request.toRegistrationRequest(); 71 | 72 | assertThat(registrationRequest.configuration.toJsonString()) 73 | .isEqualTo(getTestServiceConfig().toJsonString()); 74 | assertThat(registrationRequest.redirectUris.iterator().next()) 75 | .isEqualTo(Uri.parse("redirect_uri_unused")); 76 | } 77 | 78 | @Test 79 | public void testJsonSerialize() throws Exception { 80 | DeviceActivationRequest request = mRequestBuilder.build(); 81 | JSONObject json = request.jsonSerialize(); 82 | assertMaximalValuesInJson(request, json); 83 | assertThat(json.getJSONObject(DeviceRegistrationRequest.KEY_CONFIGURATION).toString()) 84 | .isEqualTo(request.configuration.toJson().toString()); 85 | } 86 | 87 | private void assertValues(DeviceActivationRequest request) { 88 | assertEquals("unexpected activation URI", TEST_IDP_ACTIVATION_ENDPOINT.toString(), 89 | request.activationEndpoint.toString()); 90 | assertEquals("unexpected activation code", TEST_ACTIVATION_CODE, 91 | request.activationCode); 92 | } 93 | 94 | private void assertMaximalValuesInJson(DeviceActivationRequest request, JSONObject json) 95 | throws JSONException { 96 | assertThat(json.get(DeviceActivationRequest.KEY_ENDPOINT)) 97 | .isEqualTo(request.activationEndpoint.toString()); 98 | assertThat(json.get(DeviceActivationRequest.KEY_ACTIVATION_CODE)) 99 | .isEqualTo(request.activationCode); 100 | 101 | 102 | } 103 | } -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/src/test/java/com/omnissa/idm/samples/saml/core/CurrentUserHandlerMethodArgumentResolverTest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2017 Vincenzo De Notaris 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | 17 | package com.omnissa.idm.samples.saml.core; 18 | 19 | import com.omnissa.idm.samples.saml.CommonTestSupport; 20 | import com.omnissa.idm.samples.saml.stereotypes.CurrentUser; 21 | import org.junit.Before; 22 | import org.junit.Test; 23 | import org.junit.runner.RunWith; 24 | import org.springframework.beans.factory.annotation.Autowired; 25 | import org.springframework.boot.test.context.SpringBootTest; 26 | import org.springframework.core.MethodParameter; 27 | import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; 28 | import org.springframework.security.core.userdetails.User; 29 | import org.springframework.test.context.junit4.SpringRunner; 30 | import org.springframework.web.bind.support.WebArgumentResolver; 31 | import org.springframework.web.bind.support.WebDataBinderFactory; 32 | import org.springframework.web.context.request.NativeWebRequest; 33 | import org.springframework.web.method.support.ModelAndViewContainer; 34 | 35 | import java.security.Principal; 36 | import java.util.Collections; 37 | 38 | import static org.junit.Assert.assertEquals; 39 | import static org.junit.Assert.assertFalse; 40 | import static org.junit.Assert.assertTrue; 41 | import static org.mockito.Mockito.mock; 42 | import static org.mockito.Mockito.when; 43 | 44 | 45 | @RunWith(SpringRunner.class) 46 | @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 47 | public class CurrentUserHandlerMethodArgumentResolverTest extends CommonTestSupport { 48 | 49 | @Autowired 50 | private CurrentUserHandlerMethodArgumentResolver resolver; 51 | 52 | private MethodParameter validParam; 53 | 54 | private MethodParameter notAnnotatedParam; 55 | 56 | private MethodParameter wrongTypeParam; 57 | 58 | @Before 59 | public void init() throws NoSuchMethodException { 60 | validParam = new MethodParameter( 61 | MethodSamples.class.getMethod("validUser", User.class), 0); 62 | notAnnotatedParam = new MethodParameter( 63 | MethodSamples.class.getMethod("notAnnotatedUser", User.class), 0); 64 | wrongTypeParam = new MethodParameter( 65 | MethodSamples.class.getMethod("wrongTypeUser", Object.class), 0); 66 | } 67 | 68 | @Test 69 | public void testSupportsParameter() throws NoSuchMethodException { 70 | assertTrue(resolver.supportsParameter(validParam)); 71 | assertFalse(resolver.supportsParameter(notAnnotatedParam)); 72 | assertFalse(resolver.supportsParameter(wrongTypeParam)); 73 | } 74 | 75 | @Test 76 | public void testResolveArgument() throws Exception { 77 | // given 78 | ModelAndViewContainer mavContainer = mock(ModelAndViewContainer.class); 79 | WebDataBinderFactory binderFactory = mock(WebDataBinderFactory.class); 80 | NativeWebRequest webRequest = mock(NativeWebRequest.class); 81 | User stubUser = new User(USER_NAME, "", Collections.emptyList()); 82 | Principal stubPrincipal = new UsernamePasswordAuthenticationToken(stubUser, null); 83 | when(webRequest.getUserPrincipal()).thenReturn(stubPrincipal); 84 | 85 | // when/then 86 | assertEquals(stubUser, 87 | resolver.resolveArgument(validParam, mavContainer, webRequest, binderFactory)); 88 | assertEquals(WebArgumentResolver.UNRESOLVED, 89 | resolver.resolveArgument(notAnnotatedParam, mavContainer, webRequest, binderFactory)); 90 | assertEquals(WebArgumentResolver.UNRESOLVED, 91 | resolver.resolveArgument(wrongTypeParam, mavContainer, webRequest, binderFactory)); 92 | } 93 | 94 | @SuppressWarnings("unused") 95 | private static final class MethodSamples { 96 | 97 | public void validUser(@CurrentUser User user) { 98 | } 99 | 100 | public void notAnnotatedUser(User user) { 101 | } 102 | 103 | public void wrongTypeUser(@CurrentUser Object user) { 104 | } 105 | } 106 | } 107 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/test/java/net/openid/appauth/RedirectUriRegistrationReceiverActivityTest.java: -------------------------------------------------------------------------------- 1 | package net.openid.appauth; 2 | 3 | import android.app.PendingIntent; 4 | import android.content.Context; 5 | import android.content.Intent; 6 | import android.net.Uri; 7 | 8 | import org.junit.After; 9 | import org.junit.Before; 10 | import org.junit.Test; 11 | import org.junit.runner.RunWith; 12 | import org.mockito.ArgumentCaptor; 13 | import org.mockito.Mock; 14 | import org.mockito.MockitoAnnotations; 15 | import org.robolectric.Robolectric; 16 | import org.robolectric.RobolectricGradleTestRunner; 17 | import org.robolectric.annotation.Config; 18 | 19 | import static net.openid.appauth.DeviceActivationRequest.KEY_ACTIVATION_CODE; 20 | import static org.junit.Assert.assertEquals; 21 | import static org.junit.Assert.assertTrue; 22 | import static org.mockito.Matchers.any; 23 | import static org.mockito.Matchers.anyInt; 24 | import static org.mockito.Matchers.eq; 25 | import static org.mockito.Mockito.doThrow; 26 | import static org.mockito.Mockito.verify; 27 | 28 | /** 29 | * Testing registration redirection happens correctly on the activity. 30 | */ 31 | @RunWith(RobolectricGradleTestRunner.class) 32 | @Config(constants = com.omnissa.idm.samples.appauth.BuildConfig.class, sdk = 16, manifest = "src/main/AndroidManifest.xml") 33 | public class RedirectUriRegistrationReceiverActivityTest extends OmnissaAppAuthTest { 34 | 35 | private DeviceRegistrationRequest mRequest; 36 | 37 | @Mock 38 | PendingIntent mPendingIntent; 39 | 40 | private static final Intent CODE_INTENT; 41 | 42 | private static final Uri CODE_URI = new Uri.Builder() 43 | .scheme(TEST_APP_SCHEME) 44 | .appendQueryParameter(AuthorizationResponse.KEY_STATE, TEST_STATE) 45 | .appendQueryParameter(AuthorizationResponse.KEY_AUTHORIZATION_CODE, 46 | TEST_AUTHORIZATION_CODE) 47 | .appendQueryParameter(KEY_ACTIVATION_CODE, TEST_ACTIVATION_CODE) 48 | .build(); 49 | 50 | static { 51 | CODE_INTENT = new Intent(); 52 | CODE_INTENT.setData(CODE_URI); 53 | } 54 | 55 | 56 | @Before 57 | public void setUp() { 58 | MockitoAnnotations.initMocks(this); 59 | DeviceRegistrationPendingIntentStore.getInstance().clearAll(); 60 | mRequest = getTestDeviceRegistrationRequestBuilder() 61 | .setState(TEST_STATE) 62 | .build(); 63 | } 64 | 65 | @After 66 | public void tearDown() { 67 | DeviceRegistrationPendingIntentStore.getInstance().clearAll(); 68 | } 69 | 70 | @Test 71 | public void testRedirectUriActivity() throws Exception { 72 | DeviceRegistrationPendingIntentStore.getInstance() 73 | .addPendingIntent(mRequest, mPendingIntent); 74 | RedirectUriRegistrationReceiverActivity activity = Robolectric 75 | .buildActivity(RedirectUriRegistrationReceiverActivity.class) 76 | .withIntent(CODE_INTENT) 77 | .create() 78 | .get(); 79 | 80 | ArgumentCaptor intentCaptor = ArgumentCaptor.forClass(Intent.class); 81 | verify(mPendingIntent).send(eq(activity), anyInt(), intentCaptor.capture()); 82 | 83 | Intent resultIntent = intentCaptor.getValue(); 84 | DeviceRegistrationResponse response = DeviceRegistrationResponse.fromIntent(resultIntent); 85 | assertEquals(TEST_STATE, response.state); 86 | assertEquals(TEST_AUTHORIZATION_CODE, response.authorizationCode); 87 | assertEquals(TEST_ACTIVATION_CODE, response.activationCode); 88 | assertTrue(activity.isFinishing()); 89 | } 90 | 91 | 92 | @Test 93 | public void testRedirectUriActivityWithMissingPendingIntent() throws Exception { 94 | RedirectUriRegistrationReceiverActivity activity = Robolectric 95 | .buildActivity(RedirectUriRegistrationReceiverActivity.class) 96 | .withIntent(CODE_INTENT) 97 | .create() 98 | .get(); 99 | 100 | // no pending intent found, redirect uri should be ignored and activity should finish 101 | assertTrue(activity.isFinishing()); 102 | } 103 | 104 | @Test 105 | public void testRedirectUriActivityWithCanceledPendingIntent() throws Exception { 106 | DeviceRegistrationPendingIntentStore.getInstance() 107 | .addPendingIntent(mRequest, mPendingIntent); 108 | doThrow(new PendingIntent.CanceledException()).when(mPendingIntent) 109 | .send(any(Context.class), anyInt(), any(Intent.class)); 110 | RedirectUriRegistrationReceiverActivity activity = Robolectric 111 | .buildActivity(RedirectUriRegistrationReceiverActivity.class) 112 | .withIntent(CODE_INTENT) 113 | .create() 114 | .get(); 115 | 116 | // exception thrown when trying to send pending intent, activity should finish 117 | assertTrue(activity.isFinishing()); 118 | } 119 | 120 | 121 | } 122 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/java/net/openid/appauth/DeviceActivationResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The AppAuth for Android Authors. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the 10 | * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | * express or implied. See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package net.openid.appauth; 16 | 17 | import android.support.annotation.NonNull; 18 | import android.support.annotation.Nullable; 19 | 20 | import org.json.JSONException; 21 | import org.json.JSONObject; 22 | 23 | import static net.openid.appauth.Preconditions.checkNotEmpty; 24 | import static net.openid.appauth.Preconditions.checkNotNull; 25 | 26 | /** 27 | * The response of the device activation request. 28 | * Omnissa Identity Manager service will exchange the activation code with a unique pair of 29 | * (client id, client secret) for this device. 30 | * 31 | * @see {DeviceActivationRequest} 32 | */ 33 | public class DeviceActivationResponse { 34 | 35 | static final String PARAM_CLIENT_ID = "client_id"; 36 | static final String PARAM_CLIENT_SECRET = "client_secret"; 37 | 38 | /** 39 | * The original request associated with this response. 40 | */ 41 | @NonNull 42 | public final DeviceActivationRequest request; 43 | 44 | /** 45 | * The registered client identifier. 46 | * 47 | * @see "The OAuth 2.0 Authorization 48 | * Framework" (RFC 6749), Section 4 49 | * @see "The OAuth 2.0 50 | * Authorization 51 | * Framework" (RFC 6749), Section 4.1.1 52 | */ 53 | @NonNull 54 | public final String clientId; 55 | 56 | /** 57 | * The client secret, which is part of the client credentials, if provided. 58 | * 59 | * @see 60 | * "OpenID Connect Dynamic Client Registration 1.0", Section 3.2 61 | */ 62 | @Nullable 63 | public final String clientSecret; 64 | 65 | private DeviceActivationResponse( 66 | DeviceActivationRequest mRequest, String mClientId, String mClientSecret) { 67 | this.request = mRequest; 68 | this.clientId = mClientId; 69 | this.clientSecret = mClientSecret; 70 | } 71 | 72 | public static final class Builder { 73 | @NonNull 74 | private DeviceActivationRequest mRequest; 75 | @NonNull 76 | private String mClientId; 77 | 78 | @Nullable 79 | private String mClientSecret; 80 | 81 | /** 82 | * Creates an activation response associated with the specified request. 83 | */ 84 | public Builder(@NonNull DeviceActivationRequest request) { 85 | setRequest(request); 86 | } 87 | 88 | /** 89 | * Specifies the request associated with this response. Must not be null. 90 | */ 91 | @NonNull 92 | public DeviceActivationResponse.Builder setRequest( 93 | @NonNull DeviceActivationRequest request) { 94 | mRequest = checkNotNull(request, "request cannot be null"); 95 | return this; 96 | } 97 | 98 | /** 99 | * Specifies the client identifier. 100 | */ 101 | public DeviceActivationResponse.Builder setClientId(@NonNull String clientId) { 102 | checkNotEmpty(clientId, "client ID cannot be null or empty"); 103 | mClientId = clientId; 104 | return this; 105 | } 106 | 107 | /** 108 | * Specifies the client secret. 109 | */ 110 | public DeviceActivationResponse.Builder setClientSecret(@Nullable String clientSecret) { 111 | mClientSecret = clientSecret; 112 | return this; 113 | } 114 | 115 | 116 | /** 117 | * Creates the activation response instance. 118 | */ 119 | public DeviceActivationResponse build() { 120 | return new DeviceActivationResponse( 121 | mRequest, 122 | mClientId, 123 | mClientSecret); 124 | } 125 | 126 | /** 127 | * Extracts activation response fields from a JSON object. 128 | * 129 | * @throws JSONException if the JSON is malformed or has incorrect value types for fields. 130 | */ 131 | @NonNull 132 | public DeviceActivationResponse.Builder fromResponseJson(@NonNull JSONObject json) 133 | throws JSONException { 134 | setClientId(JsonUtil.getString(json, PARAM_CLIENT_ID)); 135 | 136 | if (json.has(PARAM_CLIENT_SECRET)) { 137 | setClientSecret(json.getString(PARAM_CLIENT_SECRET)); 138 | } 139 | return this; 140 | } 141 | } 142 | 143 | } 144 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-saml2/gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # For Cygwin, ensure paths are in UNIX format before anything is touched. 46 | if $cygwin ; then 47 | [ -n "$JAVA_HOME" ] && JAVA_HOME=`cygpath --unix "$JAVA_HOME"` 48 | fi 49 | 50 | # Attempt to set APP_HOME 51 | # Resolve links: $0 may be a link 52 | PRG="$0" 53 | # Need this for relative symlinks. 54 | while [ -h "$PRG" ] ; do 55 | ls=`ls -ld "$PRG"` 56 | link=`expr "$ls" : '.*-> \(.*\)$'` 57 | if expr "$link" : '/.*' > /dev/null; then 58 | PRG="$link" 59 | else 60 | PRG=`dirname "$PRG"`"/$link" 61 | fi 62 | done 63 | SAVED="`pwd`" 64 | cd "`dirname \"$PRG\"`/" >&- 65 | APP_HOME="`pwd -P`" 66 | cd "$SAVED" >&- 67 | 68 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 69 | 70 | # Determine the Java command to use to start the JVM. 71 | if [ -n "$JAVA_HOME" ] ; then 72 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 73 | # IBM's JDK on AIX uses strange locations for the executables 74 | JAVACMD="$JAVA_HOME/jre/sh/java" 75 | else 76 | JAVACMD="$JAVA_HOME/bin/java" 77 | fi 78 | if [ ! -x "$JAVACMD" ] ; then 79 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 80 | 81 | Please set the JAVA_HOME variable in your environment to match the 82 | location of your Java installation." 83 | fi 84 | else 85 | JAVACMD="java" 86 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 87 | 88 | Please set the JAVA_HOME variable in your environment to match the 89 | location of your Java installation." 90 | fi 91 | 92 | # Increase the maximum file descriptors if we can. 93 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 94 | MAX_FD_LIMIT=`ulimit -H -n` 95 | if [ $? -eq 0 ] ; then 96 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 97 | MAX_FD="$MAX_FD_LIMIT" 98 | fi 99 | ulimit -n $MAX_FD 100 | if [ $? -ne 0 ] ; then 101 | warn "Could not set maximum file descriptor limit: $MAX_FD" 102 | fi 103 | else 104 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 105 | fi 106 | fi 107 | 108 | # For Darwin, add options to specify how the application appears in the dock 109 | if $darwin; then 110 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 111 | fi 112 | 113 | # For Cygwin, switch paths to Windows format before running java 114 | if $cygwin ; then 115 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 116 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 117 | 118 | # We build the pattern for arguments to be converted via cygpath 119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 120 | SEP="" 121 | for dir in $ROOTDIRSRAW ; do 122 | ROOTDIRS="$ROOTDIRS$SEP$dir" 123 | SEP="|" 124 | done 125 | OURCYGPATTERN="(^($ROOTDIRS))" 126 | # Add a user-defined pattern to the cygpath arguments 127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 129 | fi 130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 131 | i=0 132 | for arg in "$@" ; do 133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 135 | 136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 138 | else 139 | eval `echo args$i`="\"$arg\"" 140 | fi 141 | i=$((i+1)) 142 | done 143 | case $i in 144 | (0) set -- ;; 145 | (1) set -- "$args0" ;; 146 | (2) set -- "$args0" "$args1" ;; 147 | (3) set -- "$args0" "$args1" "$args2" ;; 148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 154 | esac 155 | fi 156 | 157 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 158 | function splitJvmOpts() { 159 | JVM_OPTS=("$@") 160 | } 161 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 162 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 163 | 164 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 165 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/test/java/net/openid/appauth/DeviceRegistrationRequestTest.java: -------------------------------------------------------------------------------- 1 | package net.openid.appauth; 2 | 3 | import android.net.Uri; 4 | 5 | import org.json.JSONException; 6 | import org.json.JSONObject; 7 | import org.junit.Before; 8 | import org.junit.Test; 9 | import org.junit.runner.RunWith; 10 | import org.robolectric.RobolectricTestRunner; 11 | import org.robolectric.annotation.Config; 12 | 13 | import static junit.framework.Assert.assertEquals; 14 | import static org.assertj.core.api.Assertions.assertThat; 15 | 16 | 17 | /** 18 | * Unit tests for the device registration request against Omnissa Identity Manager. 19 | */ 20 | @RunWith(RobolectricTestRunner.class) 21 | @Config(constants = com.omnissa.idm.samples.appauth.BuildConfig.class, sdk = 16) 22 | public class DeviceRegistrationRequestTest extends OmnissaAppAuthTest { 23 | 24 | 25 | private static final String TEST_JSON = "{\n" 26 | + " \"app_product_id\": \"" + TEST_APP_TEMPLATE + "\",\n" 27 | + " \"redirect_uri\": \"" + TEST_APP_REDIRECT_URI + "\",\n" 28 | + " \"device_name\": \"" + TEST_DEVICE_NAME + "\",\n" 29 | + " \"user_device\": \"{ \\\"info\\\" : \\\"user_device\\\" }\",\n" 30 | + " \"type\": \"" + DeviceRegistrationRequest.TYPE_REGISTER + "\",\n" 31 | + " \"state\": \"" + TEST_STATE + "\",\n" 32 | + " \"scope\": \"" + TEST_SCOPE + "\",\n" 33 | + " \"response_type\": \"" + DeviceRegistrationRequest.RESPONSE_TYPE_CODE + "\",\n" 34 | + " \"activation_uri\": \"" + TEST_IDP_ACTIVATION_ENDPOINT + "\"\n" 35 | + "}"; 36 | 37 | private DeviceRegistrationRequest.Builder mMinimalRequestBuilder; 38 | private DeviceRegistrationRequest.Builder mMaximalRequestBuilder; 39 | 40 | private JSONObject mJson; 41 | 42 | @Before 43 | public void setUp() throws JSONException { 44 | mMinimalRequestBuilder = getTestDeviceRegistrationRequestBuilder(); 45 | mMaximalRequestBuilder = 46 | getTestDeviceRegistrationRequestBuilder().setScope(TEST_SCOPE).setState(TEST_STATE); 47 | mJson = new JSONObject(TEST_JSON); 48 | } 49 | 50 | 51 | @Test 52 | public void testBuilder() { 53 | assertValues(mMinimalRequestBuilder.build()); 54 | } 55 | 56 | @Test 57 | public void testToUri() throws Exception { 58 | DeviceRegistrationRequest request = mMaximalRequestBuilder.build(); 59 | Uri requestUri = request.toUri(); 60 | assertThat(requestUri.toString()).isEqualTo( 61 | TEST_IDP_REGISTRATION_ENDPOINT + "?" + 62 | "redirect_uri=" + Uri.encode(TEST_APP_REDIRECT_URI.toString()) + 63 | "&app_product_id=" + Uri.encode(TEST_APP_TEMPLATE) + 64 | "&device_name=" + Uri.encode(TEST_DEVICE_NAME) + 65 | "&user_device=" + Uri.encode(TEST_USER_DEVICE_JSON) + 66 | "&response_type=" + DeviceRegistrationRequest.RESPONSE_TYPE_CODE + 67 | "&type=" + DeviceRegistrationRequest.TYPE_REGISTER + 68 | "&state=" + Uri.encode(TEST_STATE) + 69 | "&scope=" + Uri.encode(TEST_SCOPE) 70 | ); 71 | 72 | 73 | } 74 | 75 | @Test 76 | public void testSerialize() throws JSONException { 77 | DeviceRegistrationRequest request = mMaximalRequestBuilder.build(); 78 | JSONObject json = request.jsonSerialize(); 79 | assertMaximalValuesInJson(request, json); 80 | assertThat(json.getJSONObject(DeviceRegistrationRequest.KEY_CONFIGURATION).toString()) 81 | .isEqualTo(request.configuration.toJson().toString()); 82 | } 83 | 84 | @Test 85 | public void testJsonDeserialize() throws Exception { 86 | mJson.put(DeviceRegistrationRequest.KEY_CONFIGURATION, getTestServiceConfig().toJson()); 87 | DeviceRegistrationRequest request = DeviceRegistrationRequest.jsonDeserialize(mJson); 88 | assertThat(request.configuration.toJsonString()) 89 | .isEqualTo(getTestServiceConfig().toJsonString()); 90 | assertMaximalValuesInJson(request, mJson); 91 | } 92 | 93 | @Test 94 | public void testToAuthorizationRequest() throws Exception { 95 | AuthorizationRequest request = 96 | mMaximalRequestBuilder.build().toAuthorizationRequest("client_id"); 97 | assertEquals("unexpected client id", "client_id", request.clientId); 98 | 99 | 100 | } 101 | 102 | private void assertValues(DeviceRegistrationRequest request) { 103 | assertEquals("unexpected redirect URI", TEST_APP_REDIRECT_URI.toString(), 104 | request.redirectUri.toString()); 105 | assertEquals("unexpected register type", DeviceRegistrationRequest.TYPE_REGISTER, 106 | request.registerType); 107 | assertEquals("unexpected response type", DeviceRegistrationRequest.RESPONSE_TYPE_CODE, 108 | request.responseType); 109 | assertEquals("unexpected device name", TEST_DEVICE_NAME, 110 | request.deviceName); 111 | assertEquals("unexpected user's device info", TEST_USER_DEVICE_JSON, 112 | request.userDevice); 113 | assertEquals("unexpected user's device info", TEST_APP_TEMPLATE, 114 | request.appProductId); 115 | 116 | } 117 | 118 | private void assertMaximalValuesInJson(DeviceRegistrationRequest request, JSONObject json) 119 | throws JSONException { 120 | assertThat(json.get(DeviceRegistrationRequest.PARAM_REDIRECT_URI)) 121 | .isEqualTo(request.redirectUri.toString()); 122 | assertThat(json.get(DeviceRegistrationRequest.PARAM_RESPONSE_TYPE)) 123 | .isEqualTo(DeviceRegistrationRequest.RESPONSE_TYPE_CODE); 124 | assertThat(json.get(DeviceRegistrationRequest.PARAM_TYPE)) 125 | .isEqualTo(DeviceRegistrationRequest.TYPE_REGISTER); 126 | assertThat(json.get(DeviceRegistrationRequest.PARAM_DEVICE_NAME)) 127 | .isEqualTo(request.deviceName); 128 | assertThat(json.get(DeviceRegistrationRequest.PARAM_ACTIVATION_URI.toString())) 129 | .isEqualTo(request.activationEndpointUri.toString()); 130 | assertThat(json.get(DeviceRegistrationRequest.PARAM_APP_PRODUCT_ID)) 131 | .isEqualTo(request.appProductId); 132 | assertThat(json.get(DeviceRegistrationRequest.PARAM_SCOPE)) 133 | .isEqualTo(request.scope); 134 | assertThat(json.get(DeviceRegistrationRequest.PARAM_STATE)) 135 | .isEqualTo(request.state); 136 | assertThat(json.get(DeviceRegistrationRequest.PARAM_USER_DEVICE)) 137 | .isEqualTo(request.userDevice); 138 | 139 | } 140 | 141 | } -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/java/net/openid/appauth/DeviceRegistrationResponse.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The AppAuth for Android Authors. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the 10 | * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | * express or implied. See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package net.openid.appauth; 16 | 17 | import android.content.Intent; 18 | import android.net.Uri; 19 | import android.support.annotation.NonNull; 20 | import android.support.annotation.Nullable; 21 | 22 | import org.json.JSONException; 23 | import org.json.JSONObject; 24 | 25 | import static net.openid.appauth.AuthorizationResponse.KEY_STATE; 26 | import static net.openid.appauth.DeviceActivationRequest.KEY_ACTIVATION_CODE; 27 | import static net.openid.appauth.AdditionalParamsProcessor.extractAdditionalParams; 28 | import static net.openid.appauth.AuthorizationException.KEY_CODE; 29 | import static net.openid.appauth.Preconditions.checkNotNull; 30 | 31 | /** 32 | * Defines the response of the device registration call. 33 | */ 34 | public class DeviceRegistrationResponse { 35 | 36 | /** 37 | * The extra string used to store a {@link DeviceRegistrationResponse} in an intent by 38 | * {@link #toIntent()}. 39 | */ 40 | public static final String EXTRA_RESPONSE = "com.omnissa.idm.DeviceRegistrationResponse"; 41 | 42 | static final String KEY_REQUEST = "request"; 43 | 44 | /** 45 | * The registration request associated with this response. 46 | */ 47 | @NonNull 48 | public final DeviceRegistrationRequest request; 49 | 50 | /** 51 | * The authorization code generated by the authorization server. 52 | */ 53 | @Nullable 54 | public final String authorizationCode; 55 | 56 | /** 57 | * The activation code generated by the authorization server. 58 | */ 59 | @Nullable 60 | public final String activationCode; 61 | 62 | /** 63 | * The state as passed in the request. 64 | */ 65 | @Nullable 66 | public final String state; 67 | 68 | private DeviceRegistrationResponse(@NonNull DeviceRegistrationRequest request, 69 | @Nullable String authorizationCode, 70 | @Nullable String activationCode, 71 | @Nullable String state) { 72 | this.request = request; 73 | this.authorizationCode = authorizationCode; 74 | this.activationCode = activationCode; 75 | this.state = state; 76 | } 77 | 78 | 79 | /** 80 | * Extracts the registration response parameters from the query portion of a redirect URI. 81 | * 82 | * @param uri the returned URI 83 | */ 84 | @NonNull 85 | public static DeviceRegistrationResponse fromUri(DeviceRegistrationRequest request, 86 | @NonNull Uri uri) { 87 | return new DeviceRegistrationResponse(request, uri.getQueryParameter(KEY_CODE), 88 | uri.getQueryParameter(KEY_ACTIVATION_CODE), uri.getQueryParameter(KEY_STATE)); 89 | } 90 | 91 | /** 92 | * Produces an intent containing this registration response. This is used to deliver the 93 | * response to the registered handler after a call to 94 | * {@link DeviceAuthorizationService#performRegistrationRequest}. 95 | */ 96 | @NonNull 97 | public Intent toIntent() { 98 | Intent data = new Intent(); 99 | data.putExtra(EXTRA_RESPONSE, this.jsonSerializeString()); 100 | return data; 101 | } 102 | 103 | @NonNull 104 | private String jsonSerializeString() { 105 | JSONObject json = new JSONObject(); 106 | JsonUtil.put(json, KEY_REQUEST, request.jsonSerialize()); 107 | JsonUtil.putIfNotNull(json, KEY_CODE, authorizationCode); 108 | JsonUtil.putIfNotNull(json, KEY_ACTIVATION_CODE, activationCode); 109 | JsonUtil.putIfNotNull(json, KEY_STATE, state); 110 | return json.toString(); 111 | } 112 | 113 | /** 114 | * Extracts a registration response from an intent produced by {@link #toIntent()}. This is 115 | * used to extract the response from the intent data passed to an activity registered as the 116 | * handler for {@link DeviceAuthorizationService#performRegistrationRequest}. 117 | */ 118 | @Nullable 119 | public static DeviceRegistrationResponse fromIntent(@NonNull Intent dataIntent) { 120 | checkNotNull(dataIntent, "dataIntent must not be null"); 121 | if (!dataIntent.hasExtra(EXTRA_RESPONSE)) { 122 | return null; 123 | } 124 | 125 | try { 126 | JSONObject jsonResponse = new JSONObject(dataIntent.getStringExtra(EXTRA_RESPONSE)); 127 | 128 | if (!jsonResponse.has(KEY_REQUEST)) { 129 | throw new IllegalArgumentException( 130 | "authorization request not provided and not found in JSON"); 131 | } 132 | 133 | DeviceRegistrationRequest request = 134 | DeviceRegistrationRequest 135 | .jsonDeserialize(jsonResponse.getJSONObject(KEY_REQUEST)); 136 | 137 | return new DeviceRegistrationResponse(request, jsonResponse.getString(KEY_CODE), 138 | jsonResponse.getString(KEY_ACTIVATION_CODE), 139 | JsonUtil.getStringIfDefined(jsonResponse, 140 | KEY_STATE)); 141 | } catch (JSONException ex) { 142 | throw new IllegalArgumentException("Intent contains malformed registration response", 143 | ex); 144 | } 145 | } 146 | 147 | /** 148 | * Creates a follow-up request to exchange a received activation code for oauth2 credentials. 149 | * 150 | * @param activationEndpoint the activation endpoint 151 | */ 152 | public DeviceActivationRequest createDeviceActivationRequest(Uri activationEndpoint) { 153 | if (activationCode == null) { 154 | throw new IllegalStateException("activationCode not available for activation request"); 155 | } 156 | return new DeviceActivationRequest.Builder(activationEndpoint, 157 | request.configuration, 158 | activationCode).build(); 159 | } 160 | 161 | /** 162 | * Convert to an original AppAuth {@link AuthorizationResponse}, to be consumed by the AppAuth library. 163 | * 164 | * @param clientId the client id 165 | */ 166 | public AuthorizationResponse toAuthorizationResponse(String clientId) { 167 | return new AuthorizationResponse.Builder(request.toAuthorizationRequest(clientId)) 168 | .setAuthorizationCode(authorizationCode).build(); 169 | 170 | } 171 | } 172 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/java/net/openid/appauth/DeviceActivationRequest.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 The AppAuth for Android Authors. All Rights Reserved. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except 5 | * in compliance with the License. You may obtain a copy of the License at 6 | * 7 | * http://www.apache.org/licenses/LICENSE-2.0 8 | * 9 | * Unless required by applicable law or agreed to in writing, software distributed under the 10 | * License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either 11 | * express or implied. See the License for the specific language governing permissions and 12 | * limitations under the License. 13 | */ 14 | 15 | package net.openid.appauth; 16 | 17 | import android.net.Uri; 18 | import android.support.annotation.NonNull; 19 | 20 | import org.json.JSONException; 21 | import org.json.JSONObject; 22 | 23 | import java.util.Arrays; 24 | 25 | import static net.openid.appauth.JsonUtil.getString; 26 | import static net.openid.appauth.JsonUtil.getStringIfDefined; 27 | import static net.openid.appauth.JsonUtil.put; 28 | import static net.openid.appauth.Preconditions.checkNotNull; 29 | 30 | /** 31 | * Omnissa Identity Manager request to activate the device in echange of the activation code 32 | * and get a unique pair of clientID and secret. 33 | */ 34 | public class DeviceActivationRequest { 35 | 36 | static final String KEY_ACTIVATION_CODE = "activation_code"; 37 | static final String KEY_ENDPOINT = "endpoint"; 38 | static final String KEY_CONFIGURATION = "configuration"; 39 | 40 | /** 41 | * The service's {@link AuthorizationServiceConfiguration configuration}. 42 | * This configuration specifies how to connect to a particular OAuth provider. 43 | * Configurations may be 44 | * {@link AuthorizationServiceConfiguration#AuthorizationServiceConfiguration(Uri, 45 | * Uri, Uri) created manually}, or 46 | * {@link AuthorizationServiceConfiguration#fetchFromUrl(Uri, 47 | * AuthorizationServiceConfiguration.RetrieveConfigurationCallback) 48 | * via an OpenID Connect Discovery Document}. 49 | */ 50 | @NonNull 51 | public final AuthorizationServiceConfiguration configuration; 52 | 53 | /** 54 | * The activation endpoint. As the {@link AuthorizationServiceConfiguration} does not contain our special activation endpoint, we need to add it here. 55 | */ 56 | @NonNull 57 | public final Uri activationEndpoint; 58 | 59 | /** 60 | * The activation code to redeem. 61 | */ 62 | @NonNull 63 | public final String activationCode; 64 | 65 | 66 | protected DeviceActivationRequest( 67 | @NonNull AuthorizationServiceConfiguration configuration, 68 | @NonNull Uri activationEndpoint, @NonNull String activationCode 69 | ) { 70 | this.configuration = configuration; 71 | this.activationCode = activationCode; 72 | this.activationEndpoint = activationEndpoint; 73 | } 74 | 75 | /** 76 | * Reads a registration request from a JSON string representation produced by 77 | * {@link #jsonSerialize()}. 78 | * 79 | * @throws JSONException if the provided JSON does not match the expected structure. 80 | */ 81 | public static DeviceActivationRequest jsonDeserialize(@NonNull JSONObject json) 82 | throws JSONException { 83 | checkNotNull(json, "json must not be null"); 84 | 85 | Builder builder = new DeviceActivationRequest.Builder( 86 | Uri.parse(getString(json, KEY_ENDPOINT)), 87 | AuthorizationServiceConfiguration.fromJson(json.getJSONObject(KEY_CONFIGURATION)), 88 | getStringIfDefined(json, KEY_ACTIVATION_CODE)); 89 | 90 | return builder.build(); 91 | } 92 | 93 | /** 94 | * @return The activation code. 95 | */ 96 | @NonNull 97 | public String getActivationCode() { 98 | return activationCode; 99 | } 100 | 101 | /** 102 | * @return The activation endpoint. 103 | */ 104 | @NonNull 105 | public Uri getActivationEndpoint() { 106 | return activationEndpoint; 107 | } 108 | 109 | /** 110 | * Create the expected registration request from AppAuth library. 111 | * 112 | * @return The registration request. 113 | */ 114 | public RegistrationRequest toRegistrationRequest() { 115 | // @todo For now, we do not put back the redirect URI 116 | return new RegistrationRequest.Builder(configuration, 117 | Arrays.asList(Uri.parse("redirect_uri_unused"))) 118 | .build(); 119 | } 120 | 121 | /** 122 | * Produces a JSON representation of the activation request for persistent storage or 123 | * local transmission (e.g. between activities). 124 | */ 125 | @NonNull 126 | public JSONObject jsonSerialize() { 127 | JSONObject json = new JSONObject(); 128 | put(json, KEY_ENDPOINT, activationEndpoint.toString()); 129 | put(json, KEY_ACTIVATION_CODE, activationCode); 130 | put(json, KEY_CONFIGURATION, configuration.toJson()); 131 | return json; 132 | } 133 | 134 | /** 135 | * Creates instances of {@link DeviceActivationRequest}. 136 | */ 137 | public static final class Builder { 138 | @NonNull 139 | private AuthorizationServiceConfiguration mConfiguration; 140 | 141 | @NonNull 142 | private String mActivationCode; 143 | 144 | @NonNull 145 | private Uri mActivationEndpoint; 146 | 147 | /** 148 | * Creates a device activation request builder with the specified mandatory properties. 149 | */ 150 | public Builder( 151 | @NonNull Uri activationEndpoint, 152 | @NonNull AuthorizationServiceConfiguration configuration, 153 | @NonNull String activationCode 154 | ) { 155 | setActivationEnpoint(activationEndpoint); 156 | setConfiguration(configuration); 157 | setActivationCode(activationCode); 158 | } 159 | 160 | private Builder setActivationEnpoint(Uri activationEndpoint) { 161 | this.mActivationEndpoint = activationEndpoint; 162 | return this; 163 | } 164 | 165 | 166 | public Builder setActivationCode(@NonNull String activationCode) { 167 | this.mActivationCode = activationCode; 168 | return this; 169 | } 170 | 171 | /** 172 | * Specifies the authorization service configuration for the request, which must not 173 | * be null or empty. 174 | */ 175 | @NonNull 176 | public Builder setConfiguration(@NonNull AuthorizationServiceConfiguration configuration) { 177 | mConfiguration = checkNotNull(configuration); 178 | return this; 179 | } 180 | 181 | /** 182 | * Constructs the activation request. 183 | */ 184 | @NonNull 185 | public DeviceActivationRequest build() { 186 | return new DeviceActivationRequest( 187 | mConfiguration, 188 | mActivationEndpoint, 189 | mActivationCode); 190 | } 191 | } 192 | } 193 | -------------------------------------------------------------------------------- /samples/webapp-spring-boot-oauth2-resource-server/src/main/java/com/omnissa/idm/samples/oauth2/OmnissaValidateTokenServices.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.omnissa.idm.samples.oauth2; 17 | 18 | import org.springframework.http.HttpHeaders; 19 | import org.springframework.security.core.AuthenticationException; 20 | import org.springframework.security.oauth2.common.OAuth2AccessToken; 21 | import org.springframework.security.oauth2.common.exceptions.InvalidTokenException; 22 | import org.springframework.security.oauth2.provider.OAuth2Authentication; 23 | import org.springframework.security.oauth2.provider.token.ResourceServerTokenServices; 24 | import org.springframework.security.oauth2.provider.token.store.JwtTokenStore; 25 | import org.springframework.web.client.RestOperations; 26 | import org.springframework.web.client.RestTemplate; 27 | 28 | import java.net.URI; 29 | import java.net.URISyntaxException; 30 | import java.util.Date; 31 | import java.util.Map; 32 | import java.util.logging.Logger; 33 | 34 | /** 35 | * Validates an Access Token issued by Omnissa Identity Manager and populates user's logged-in information (by reading the access token content). 36 | *

37 | * It will validate either locally or using the API on Identity Manager. 38 | */ 39 | public class OmnissaValidateTokenServices implements ResourceServerTokenServices { 40 | 41 | private static Logger logger = Logger.getLogger(OmnissaValidateTokenServices.class.getSimpleName()); 42 | 43 | private static final String ISSUER_KEY = "iss"; 44 | private static final String ISSUED_AT_KEY = "iat"; 45 | public static final long ALLOWED_SKEW_IN_MS = 1000; 46 | 47 | private URI validateTokenUrl; 48 | private boolean validateLocally = true; 49 | private RestOperations restTemplate; 50 | private JwtTokenStore tokenStore; 51 | private final String expectedIssuer; 52 | 53 | public OmnissaValidateTokenServices(String validateTokenUrl, JwtTokenStore tokenStore) throws URISyntaxException { 54 | this.validateTokenUrl = new URI(validateTokenUrl); 55 | this.tokenStore = tokenStore; 56 | this.expectedIssuer = inferExpectedIssuer(validateTokenUrl); 57 | this.restTemplate = new RestTemplate(); 58 | } 59 | 60 | /** 61 | * Calculate the expected issuer URL from the given token URL. 62 | * (we could hard-code the expected URL as well, but for demo purposes, it is easier to infer it). 63 | */ 64 | private String inferExpectedIssuer(String validateTokenUrl) { 65 | int indexOfSaas = validateTokenUrl.indexOf("/SAAS"); 66 | if (indexOfSaas < 0) { 67 | throw new IllegalArgumentException("Can not infer expected issuer URL from validation URL: " + validateTokenUrl); 68 | } 69 | return validateTokenUrl.substring(0, indexOfSaas) + "/SAAS/auth"; 70 | } 71 | 72 | @Override 73 | public OAuth2Authentication loadAuthentication(String accessToken) throws AuthenticationException, InvalidTokenException { 74 | // This call is already checking for the signature and some basic expiration dates 75 | OAuth2AccessToken oAuth2AccessToken = tokenStore.readAccessToken(accessToken); 76 | if (oAuth2AccessToken == null) { 77 | throw new InvalidTokenException("Invalid access token: " + accessToken); 78 | } else if (oAuth2AccessToken.isExpired()) { 79 | throw new InvalidTokenException("Access token expired: " + oAuth2AccessToken.getExpiration()); 80 | } 81 | 82 | if (validateLocally) { 83 | validateAccessTokenLocally(oAuth2AccessToken); 84 | } else { 85 | validateAccessToken(accessToken); 86 | } 87 | 88 | OAuth2Authentication result = tokenStore.readAuthentication(accessToken); 89 | if (result == null) { 90 | // in case of race condition 91 | throw new InvalidTokenException("Invalid access token, could not extract authentication information: " + accessToken); 92 | } 93 | return result; 94 | } 95 | 96 | /** 97 | * Check the access token locally by validating additional information. 98 | * will throw {@link InvalidTokenException} on errors. 99 | * 100 | * @param accessToken the decoded access token used to access this resource server APIs 101 | */ 102 | private void validateAccessTokenLocally(OAuth2AccessToken accessToken) { 103 | logger.info("Validate access token locally: " + accessToken.getAdditionalInformation()); 104 | 105 | long now = new Date().getTime() / 1000; 106 | Map map = accessToken.getAdditionalInformation(); 107 | 108 | // check issuer 109 | String issuer = (String) map.get(ISSUER_KEY); 110 | if (issuer == null || !issuer.equals(expectedIssuer)) { 111 | throw new InvalidTokenException(String.format("Invalid issuer: '%s', expected: '%s'", issuer, expectedIssuer)); 112 | } 113 | 114 | // check iat. Allow for a time skew between the different parties 115 | Object issuedAt = map.get(ISSUED_AT_KEY); 116 | if (issuedAt == null || !(issuedAt instanceof Integer)) { 117 | throw new InvalidTokenException("Missing or invalid 'iat' key, expecting a valid timestamp value."); 118 | } 119 | if ((Integer) issuedAt > now + ALLOWED_SKEW_IN_MS) { 120 | throw new InvalidTokenException("Token has been issued in the future: " + issuedAt); 121 | } 122 | 123 | // check audience 124 | // The Spring OAuth2 filter will check the audience matches the resource ID(s) defined in the configuration YAML file 125 | logger.info("The access token has been successfully validated locally."); 126 | } 127 | 128 | /** 129 | * Call the Omnissa endpoint to validate the access token. 130 | */ 131 | private void validateAccessToken(String accessToken) { 132 | HttpHeaders headers = new HttpHeaders(); 133 | headers.set("Authorization", "Bearer " + accessToken); 134 | logger.info("Validate the token remotely using: " + this.validateTokenUrl); 135 | String isValid = restTemplate.getForObject(this.validateTokenUrl, String.class); 136 | if (isValid == null || Boolean.FALSE.toString().equals(isValid)) { 137 | throw new InvalidTokenException("The token is not valid: " + accessToken); 138 | } 139 | } 140 | 141 | @Override 142 | public OAuth2AccessToken readAccessToken(String accessToken) { 143 | return tokenStore.readAccessToken(accessToken); 144 | } 145 | 146 | public void setValidateLocally(boolean validateLocally) { 147 | this.validateLocally = validateLocally; 148 | } 149 | 150 | public void setRestTemplate(RestOperations restTemplate) { 151 | this.restTemplate = restTemplate; 152 | } 153 | } 154 | -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/test/java/net/openid/appauth/DeviceRegistrationResponseTest.java: -------------------------------------------------------------------------------- 1 | package net.openid.appauth; 2 | 3 | import android.content.Intent; 4 | import android.net.Uri; 5 | 6 | import org.json.JSONException; 7 | import org.json.JSONObject; 8 | import org.junit.Before; 9 | import org.junit.Test; 10 | import org.junit.runner.RunWith; 11 | import org.robolectric.RobolectricTestRunner; 12 | import org.robolectric.annotation.Config; 13 | 14 | import static net.openid.appauth.AuthorizationException.KEY_CODE; 15 | import static net.openid.appauth.AuthorizationResponse.KEY_STATE; 16 | import static net.openid.appauth.DeviceActivationRequest.KEY_ACTIVATION_CODE; 17 | import static net.openid.appauth.DeviceRegistrationResponse.EXTRA_RESPONSE; 18 | import static net.openid.appauth.DeviceRegistrationResponse.KEY_REQUEST; 19 | import static org.assertj.core.api.Assertions.assertThat; 20 | 21 | /** 22 | * Unit tests for {@link DeviceRegistrationResponse} 23 | */ 24 | @RunWith(RobolectricTestRunner.class) 25 | @Config(constants = com.omnissa.idm.samples.appauth.BuildConfig.class, sdk = 16) 26 | public class DeviceRegistrationResponseTest extends OmnissaAppAuthTest { 27 | 28 | private static final String TEST_JSON = "{\n" 29 | + " \"code\": \"" + TEST_AUTHORIZATION_CODE + "\",\n" 30 | + " \"activation_code\": \"" + TEST_ACTIVATION_CODE + "\",\n" 31 | + " \"state\": \"" + TEST_STATE + "\"\n" 32 | + "}"; 33 | 34 | private static final Uri TEST_REGISTRATION_REDIRECT_URI = 35 | Uri.parse( 36 | "scheme://my-redirect-uri?activation_code=" + TEST_ACTIVATION_CODE + "&code=" + 37 | TEST_AUTHORIZATION_CODE + "&state=" + TEST_STATE); 38 | 39 | private JSONObject mJson; 40 | 41 | @Before 42 | public void setUp() throws Exception { 43 | mJson = new JSONObject(TEST_JSON); 44 | } 45 | 46 | @Test 47 | public void fromUri() throws Exception { 48 | DeviceRegistrationResponse response = DeviceRegistrationResponse 49 | .fromUri(getTestDeviceRegistrationRequestBuilder().build(), 50 | TEST_REGISTRATION_REDIRECT_URI); 51 | assertThat(response.activationCode).isEqualTo(TEST_ACTIVATION_CODE); 52 | assertThat(response.authorizationCode).isEqualTo(TEST_AUTHORIZATION_CODE); 53 | assertThat(response.state).isEqualTo(TEST_STATE); 54 | } 55 | 56 | @Test 57 | public void fromUriWithNoParams() throws Exception { 58 | DeviceRegistrationResponse response = DeviceRegistrationResponse 59 | .fromUri(getTestDeviceRegistrationRequestBuilder().build(), 60 | Uri.parse("uri-with-no-params")); 61 | assertThat(response.activationCode).isNull(); 62 | assertThat(response.authorizationCode).isNull(); 63 | assertThat(response.state).isNull(); 64 | } 65 | 66 | @Test 67 | public void toIntent() throws Exception { 68 | DeviceRegistrationResponse response = DeviceRegistrationResponse 69 | .fromUri(getTestDeviceRegistrationRequestBuilder().build(), 70 | TEST_REGISTRATION_REDIRECT_URI); 71 | Intent intent = response.toIntent(); 72 | 73 | assertThat(intent.getStringExtra(EXTRA_RESPONSE)).isNotNull(); 74 | JSONObject json = new JSONObject(intent.getStringExtra(EXTRA_RESPONSE)); 75 | 76 | assertThat(json.getJSONObject(KEY_REQUEST).toString()) 77 | .isEqualTo(response.request.jsonSerialize().toString()); 78 | assertThat(json.getString(KEY_CODE)).isEqualTo(TEST_AUTHORIZATION_CODE); 79 | assertThat(json.getString(KEY_ACTIVATION_CODE)).isEqualTo(TEST_ACTIVATION_CODE); 80 | assertThat(json.getString(KEY_STATE)).isEqualTo(TEST_STATE); 81 | } 82 | 83 | @Test 84 | public void fromIntent() throws Exception { 85 | Intent intent = new Intent(); 86 | DeviceRegistrationRequest request = getTestDeviceRegistrationRequestBuilder().build(); 87 | mJson.put(KEY_REQUEST, request.jsonSerialize()); 88 | intent.putExtra(EXTRA_RESPONSE, mJson.toString()); 89 | DeviceRegistrationResponse response = DeviceRegistrationResponse 90 | .fromIntent(intent); 91 | 92 | assertThat(response.activationCode).isEqualTo(TEST_ACTIVATION_CODE); 93 | assertThat(response.authorizationCode).isEqualTo(TEST_AUTHORIZATION_CODE); 94 | assertThat(response.state).isEqualTo(TEST_STATE); 95 | assertThat(response.request.jsonSerialize().toString()) 96 | .isEqualTo(request.jsonSerialize().toString()); 97 | } 98 | 99 | @Test(expected = IllegalArgumentException.class) 100 | public void fromIntentWithoutRequestThrowsException() throws Exception { 101 | Intent intent = new Intent(); 102 | intent.putExtra(EXTRA_RESPONSE, mJson.toString()); 103 | DeviceRegistrationResponse.fromIntent(intent); 104 | } 105 | 106 | @Test(expected = IllegalArgumentException.class) 107 | public void fromIntentWithBadExtraThrowsException() throws Exception { 108 | Intent intent = new Intent(); 109 | intent.putExtra(EXTRA_RESPONSE, "{badJson}"); 110 | DeviceRegistrationResponse.fromIntent(intent); 111 | } 112 | 113 | @Test 114 | public void fromIntentWithNoExtraReturnsNull() throws Exception { 115 | DeviceRegistrationResponse response = DeviceRegistrationResponse.fromIntent(new Intent()); 116 | assertThat(response).isNull(); 117 | } 118 | 119 | 120 | @Test 121 | public void createDeviceActivationRequest() throws Exception { 122 | DeviceRegistrationResponse response = DeviceRegistrationResponse 123 | .fromUri(getTestDeviceRegistrationRequestBuilder().build(), 124 | TEST_REGISTRATION_REDIRECT_URI); 125 | DeviceActivationRequest request = 126 | response.createDeviceActivationRequest(TEST_IDP_ACTIVATION_ENDPOINT); 127 | assertThat(request.activationCode).isEqualTo(TEST_ACTIVATION_CODE); 128 | assertThat(request.activationEndpoint).isEqualTo(TEST_IDP_ACTIVATION_ENDPOINT); 129 | } 130 | 131 | @Test(expected = IllegalStateException.class) 132 | public void createDeviceActivationRequestWithNoActivationCode() throws Exception { 133 | DeviceRegistrationResponse response = DeviceRegistrationResponse 134 | .fromUri(getTestDeviceRegistrationRequestBuilder().build(), 135 | Uri.parse("scheme://my-redirect-uri-no-params")); 136 | response.createDeviceActivationRequest(TEST_IDP_ACTIVATION_ENDPOINT); 137 | } 138 | 139 | @Test 140 | public void toAuthorizationResponse() throws Exception { 141 | DeviceRegistrationResponse response = DeviceRegistrationResponse 142 | .fromUri(getTestDeviceRegistrationRequestBuilder().build(), 143 | TEST_REGISTRATION_REDIRECT_URI); 144 | AuthorizationResponse authResponse = response.toAuthorizationResponse(TEST_CLIENT_ID); 145 | assertThat(authResponse.authorizationCode).isEqualTo(TEST_AUTHORIZATION_CODE); 146 | } 147 | 148 | @Test(expected = IllegalArgumentException.class) 149 | public void toAuthorizationResponseWithNoClientId() throws Exception { 150 | DeviceRegistrationResponse response = DeviceRegistrationResponse 151 | .fromUri(getTestDeviceRegistrationRequestBuilder().build(), 152 | TEST_REGISTRATION_REDIRECT_URI); 153 | response.toAuthorizationResponse(""); 154 | } 155 | } -------------------------------------------------------------------------------- /samples/webapp-spring-boot-oauth2-resource-server/README.md: -------------------------------------------------------------------------------- 1 | Resource Server with Omnissa Identity Manager 2 | ============================================ 3 | 4 | This demo application shows the use of Spring Boot and its built-in OAuth2 capabilities to 5 | build a resource server: a server whose APIs to access resources are protected with an OAuth2 Access Token 6 | generated by Omnissa Identity Manager. 7 | 8 | A nice picture from Pivotal describes the relationship between the authorization server (Omnissa Identity Manager) and 9 | the resource server (your application): 10 | 11 | ![OAuth2 entities][pivotal-blog] 12 | 13 | ## Building the project 14 | 15 | ### Prerequisites 16 | 17 | - You need a [Omnissa Identity Manager organization](http://www.air-watch.com/omnissa-identity-manager-free-trial), like https://dev.omnissaidentity.asia, where you have __admin__ access. 18 | - The project requires JDK 8 19 | 20 | ### Building from IDE 21 | 22 | * Clone this project. 23 | * Then import the root folder. You can run the main class `ResourceApplication`. 24 | 25 | ### Building from the Command line 26 | 27 | You can run the app by using: 28 | `$ mvn spring-boot:run` 29 | 30 | or by building the jar file and running it with `mvn package` and `java -jar target/*.jar` (per the Spring Boot docs and other available documentation). 31 | or running in your IDE (run the `ResourceApplication`). 32 | 33 | ### Configure the Demo App 34 | 35 | * Edit the file `./src/main/resources/application.yml` to set your own Omnissa Identity Manager organization URL in the defined endpoints 36 | 37 | ```yaml 38 | omnissa: 39 | resource: 40 | userInfoUri: /SAAS/jersey/manager/api/userinfo 41 | checkTokenUri: /SAAS/API/1.0/REST/auth/token?attribute=isValid 42 | localValidation: true 43 | id: /SAAS/auth/oauthtoken 44 | jwt: 45 | keyUri: /SAAS/API/1.0/REST/auth/token?attribute=publicKey 46 | ``` 47 | 48 | The `localValidation` option can be set to `false` if you want to validate the token on the Identity Manager authorization server. 49 | 50 | ### Test the application 51 | 52 | The web application will be available on `http://localhost:8080`. 53 | You need to obtain an Access Token from Omnissa Identity Manager to access the resources on your app. 54 | 55 | #### Obtain an Access Token 56 | We can use the `client_credentials` grant for example to obtain an access token. 57 | A pre-registered client with the `client_credentials` needs to be defined in Omnissa Identity Manager admin console. 58 | On the provided demo tenant, to obtain an Access Token, use: 59 | 60 | ``` 61 | $ curl -u rs.webapp.samples.omnissa.com:2vxG98JcFYOcKJQignBmOjhwWCvtXlZO2PIRbs1I933WvoAp https://dev.omnissaidentity.asia/SAAS/auth/oauthtoken -d "grant_type=client_credentials" 62 | {"access_token":"eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJqdGkiOiIwYmVlOTFlMi04OTY5LTRkZGUtYWUzNC03NjQ2NTgyYTdjMzEiLCJwcm4iOiJycy53ZWJhcHAuc2FtcGxlcy52bXdhcmUuY29tQERFViIsImRvbWFpbiI6IkxvY2FsIFVzZXJzIiwidXNlcl9pZCI6IjQyOTMzIiwiYXV0aF90aW1lIjoxNDc5MjM3Nzk3LCJpc3MiOiJodHRwczovL2Rldi52bXdhcmVpZGVudGl0eS5hc2lhL1NBQVMvYXV0aCIsImF1ZCI6Imh0dHBzOi8vZGV2LnZtd2FyZWlkZW50aXR5LmFzaWEvU0FBUy9hdXRoL29hdXRodG9rZW4iLCJjdHgiOiJbe1wibXRkXCI6XCJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YWM6Y2xhc3NlczpQYXNzd29yZFByb3RlY3RlZFRyYW5zcG9ydFwiLFwiaWF0XCI6MTQ3OTIzNzc5OCxcImlkXCI6MzUxNTd9XSIsInNjcCI6ImFkbWluIiwiaWRwIjoiMCIsImVtbCI6Ik9BdXRoQ2xpZW50X3Jzd2ViYXBwc2FtcGxlc3Ztd2FyZWNvbUBub3JlcGx5LmNvbSIsImNpZCI6InJzLndlYmFwcC5zYW1wbGVzLnZtd2FyZS5jb20iLCJkaWQiOiIiLCJ3aWQiOiIiLCJleHAiOjE0NzkyNTkzOTgsImlhdCI6MTQ3OTIzNzc5OCwic3ViIjoiZDA0YzYyZjEtYTRkZC00MTJjLTg0MzUtOWYzMjY2NTdkNWI5IiwicHJuX3R5cGUiOiJTRVJWSUNFIn0.pTLIUJQ91WfDMmzntBM9kP_4G1zxO-SH8wyWYqUlfIzI--dH-oq9pCDQ8Df84QQ27ZfCCxfTyDOFSUhHxqALIPc0_WHaq-sm8hVlOksLQRMgMcc3avLFHKmROr3IU_PZTnJrtUFYlM8I8fJMHbhsxgKECYxsTGz4JW6vVMnRp7s","token_type":"Bearer","expires_in":21599,"refresh_token":"qp1YA6gDhkGaKIMZk5iIgt0RSEpc24hJ","scope":"admin"} 63 | ``` 64 | 65 | You could also access this resource server from the [other web app example](https://github.com/omnissa/idm/tree/master/samples/webapp-spring-boot-oauth2) that authenticates end-users using OAuth2 and the 66 | `authorization_code` grant. 67 | 68 | #### Use the Access Token 69 | We can now use the given access_token to access the resource: 70 | ``` 71 | $ curl -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJqdGkiOiIwYmVlOTFlMi04OTY5LTRkZGUtYWUzNC03NjQ2NTgyYTdjMzEiLCJwcm4iOiJycy53ZWJhcHAuc2FtcGxlcy52bXdhcmUuY29tQERFViIsImRvbWFpbiI6IkxvY2FsIFVzZXJzIiwidXNlcl9pZCI6IjQyOTMzIiwiYXV0aF90aW1lIjoxNDc5MjM3Nzk3LCJpc3MiOiJodHRwczovL2Rldi52bXdhcmVpZGVudGl0eS5hc2lhL1NBQVMvYXV0aCIsImF1ZCI6Imh0dHBzOi8vZGV2LnZtd2FyZWlkZW50aXR5LmFzaWEvU0FBUy9hdXRoL29hdXRodG9rZW4iLCJjdHgiOiJbe1wibXRkXCI6XCJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YWM6Y2xhc3NlczpQYXNzd29yZFByb3RlY3RlZFRyYW5zcG9ydFwiLFwiaWF0XCI6MTQ3OTIzNzc5OCxcImlkXCI6MzUxNTd9XSIsInNjcCI6ImFkbWluIiwiaWRwIjoiMCIsImVtbCI6Ik9BdXRoQ2xpZW50X3Jzd2ViYXBwc2FtcGxlc3Ztd2FyZWNvbUBub3JlcGx5LmNvbSIsImNpZCI6InJzLndlYmFwcC5zYW1wbGVzLnZtd2FyZS5jb20iLCJkaWQiOiIiLCJ3aWQiOiIiLCJleHAiOjE0NzkyNTkzOTgsImlhdCI6MTQ3OTIzNzc5OCwic3ViIjoiZDA0YzYyZjEtYTRkZC00MTJjLTg0MzUtOWYzMjY2NTdkNWI5IiwicHJuX3R5cGUiOiJTRVJWSUNFIn0.pTLIUJQ91WfDMmzntBM9kP_4G1zxO-SH8wyWYqUlfIzI--dH-oq9pCDQ8Df84QQ27ZfCCxfTyDOFSUhHxqALIPc0_WHaq-sm8hVlOksLQRMgMcc3avLFHKmROr3IU_PZTnJrtUFYlM8I8fJMHbhsxgKECYxsTGz4JW6vVMnRp7s' http://localhost:8080/resource 72 | Resource granted to rs.webapp.samples.omnissa.com@DEV! 73 | ``` 74 | 75 | ### What's happening? 76 | 77 | The Access Token granted by Omnissa Identity Manager is used to access resources on the resource server. 78 | The resource server uses the Spring OAuth2 filter (`OAuth2AuthenticationProcessingFilter`) to protect all its resources with an OAuth2 token. 79 | It also validates the given access token to make sure this token was intended for it. 80 | 81 | If you try to access the un-protected "/" URL, this works: 82 | ``` 83 | $ curl http://localhost:8080/ 84 | Home resource (unprotected) 85 | ``` 86 | 87 | If you try to access the protected URL, the OAuth2 filter is trying to extract the access token from the Authorization header and it will fail if not found: 88 | ``` 89 | $ curl http://localhost:8080/resource 90 | {"error":"unauthorized","error_description":"Full authentication is required to access this resource"} 91 | ``` 92 | 93 | If you try to access the protected URL with an expired token, as we are validating it in our implementation, the request will fail too: 94 | ``` 95 | $ curl -H 'Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJSUzI1NiJ9.eyJqdGkiOiJlZWNlYTkxYS1hNWI1LTQ3YzYtYTA3Ny02NmFmMzQxZWM5YTUiLCJwcm4iOiJycy53ZWJhcHAuc2FtcGxlcy52bXdhcmUuY29tQERFViIsImRvbWFpbiI6IkxvY2FsIFVzZXJzIiwidXNlcl9pZCI6IjQyOTMzIiwiYXV0aF90aW1lIjoxNDc5MTc1MDExLCJpc3MiOiJodHRwczovL2Rldi52bXdhcmVpZGVudGl0eS5hc2lhL1NBQVMvYXV0aCIsImF1ZCI6Imh0dHBzOi8vZGV2LnZtd2FyZWlkZW50aXR5LmFzaWEvU0FBUy9hdXRoL29hdXRodG9rZW4iLCJjdHgiOiJbe1wibXRkXCI6XCJ1cm46b2FzaXM6bmFtZXM6dGM6U0FNTDoyLjA6YWM6Y2xhc3NlczpQYXNzd29yZFByb3RlY3RlZFRyYW5zcG9ydFwiLFwiaWF0XCI6MTQ3OTE3NTAxMSxcImlkXCI6MzUxNTd9XSIsInNjcCI6ImFkbWluIiwiaWRwIjoiMCIsImVtbCI6Ik9BdXRoQ2xpZW50X3Jzd2ViYXBwc2FtcGxlc3Ztd2FyZWNvbUBub3JlcGx5LmNvbSIsImNpZCI6InJzLndlYmFwcC5zYW1wbGVzLnZtd2FyZS5jb20iLCJkaWQiOiIiLCJ3aWQiOiIiLCJleHAiOjE0NzkxOTY2MTEsImlhdCI6MTQ3OTE3NTAxMSwic3ViIjoiZDA0YzYyZjEtYTRkZC00MTJjLTg0MzUtOWYzMjY2NTdkNWI5IiwicHJuX3R5cGUiOiJTRVJWSUNFIn0.pWdZSY3up7FOb7LoO1AZs1G6Z1ZAvOWUOZmcbDfIjkI0thmI6F3aVKXVqt6HyPSRTpjB1wAHPTpSvbtiphhIPzizkAl0CHhStst1PRnrAZTE6_j7jd9oy1JK4A6dsQnEFtM5koq5jHCpY4EF-Kr3mkYJtJZ2sR23pQ62oPSsGlU' http://localhost:8080/resource 96 | {"error":"invalid_token","error_description":"Access token expired: Mon Nov 14 23:56:51 PST 2016"} 97 | ``` 98 | 99 | [pivotal-blog]: http://blog.gopivotal.com/wp-content/uploads/2012/10/cdraw.png -------------------------------------------------------------------------------- /samples/webapp-spring-boot-oauth2/src/main/java/com/omnissa/idm/samples/oauth2/SocialApplication.java: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright 2012-2016 the original author or authors. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package com.omnissa.idm.samples.oauth2; 17 | 18 | import org.springframework.beans.factory.annotation.Autowired; 19 | import org.springframework.boot.SpringApplication; 20 | import org.springframework.boot.autoconfigure.SpringBootApplication; 21 | import org.springframework.boot.autoconfigure.security.oauth2.resource.PrincipalExtractor; 22 | import org.springframework.boot.autoconfigure.security.oauth2.resource.ResourceServerProperties; 23 | import org.springframework.boot.autoconfigure.security.oauth2.resource.UserInfoTokenServices; 24 | import org.springframework.boot.context.properties.ConfigurationProperties; 25 | import org.springframework.boot.context.properties.NestedConfigurationProperty; 26 | import org.springframework.boot.web.servlet.FilterRegistrationBean; 27 | import org.springframework.context.annotation.Bean; 28 | import org.springframework.core.annotation.Order; 29 | import org.springframework.security.config.annotation.web.builders.HttpSecurity; 30 | import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter; 31 | import org.springframework.security.oauth2.client.OAuth2ClientContext; 32 | import org.springframework.security.oauth2.client.OAuth2RestTemplate; 33 | import org.springframework.security.oauth2.client.filter.OAuth2ClientAuthenticationProcessingFilter; 34 | import org.springframework.security.oauth2.client.filter.OAuth2ClientContextFilter; 35 | import org.springframework.security.oauth2.client.token.grant.code.AuthorizationCodeResourceDetails; 36 | import org.springframework.security.oauth2.config.annotation.web.configuration.EnableOAuth2Client; 37 | import org.springframework.security.web.authentication.LoginUrlAuthenticationEntryPoint; 38 | import org.springframework.security.web.authentication.www.BasicAuthenticationFilter; 39 | import org.springframework.security.web.csrf.CookieCsrfTokenRepository; 40 | import org.springframework.web.bind.annotation.RequestMapping; 41 | import org.springframework.web.bind.annotation.RestController; 42 | import org.springframework.web.filter.CompositeFilter; 43 | 44 | import javax.servlet.Filter; 45 | import java.security.Principal; 46 | import java.util.ArrayList; 47 | import java.util.LinkedHashMap; 48 | import java.util.List; 49 | import java.util.Map; 50 | 51 | @SpringBootApplication 52 | @RestController 53 | @EnableOAuth2Client 54 | @Order(6) 55 | public class SocialApplication extends WebSecurityConfigurerAdapter { 56 | 57 | @Autowired 58 | OAuth2ClientContext oauth2ClientContext; 59 | 60 | /** 61 | * This endpoint requires the user to be authenticated: this /user endpoint is now secured with cookies created 62 | * when the user authenticates through Omnissa Identity Manager. 63 | * Spring will populate the "Principal" object with the logged-in user's information. 64 | */ 65 | @RequestMapping("/user") 66 | public Map user(Principal principal) { 67 | Map map = new LinkedHashMap<>(); 68 | map.put("name", principal.getName()); 69 | return map; 70 | } 71 | 72 | @Override 73 | protected void configure(HttpSecurity http) throws Exception { 74 | // @formatter:off 75 | http.antMatcher("/**").authorizeRequests().antMatchers("/", "/login**", "/webjars/**").permitAll().anyRequest() 76 | .authenticated().and().exceptionHandling() 77 | .authenticationEntryPoint(new LoginUrlAuthenticationEntryPoint("/")).and().logout() 78 | .logoutSuccessUrl("/").permitAll().and().csrf() 79 | .csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse()).and() 80 | .addFilterBefore(ssoFilter(), BasicAuthenticationFilter.class); 81 | // @formatter:on 82 | } 83 | 84 | public static void main(String[] args) { 85 | SpringApplication.run(SocialApplication.class, args); 86 | } 87 | 88 | /** 89 | * Register the filter OAuth2ClientContextFilter that will handle the redirect to Omnissa Identity Manager 90 | * if the user is not authenticated. 91 | */ 92 | @Bean 93 | public FilterRegistrationBean oauth2ClientFilterRegistration(OAuth2ClientContextFilter filter) { 94 | FilterRegistrationBean registration = new FilterRegistrationBean(); 95 | registration.setFilter(filter); 96 | registration.setOrder(-100); 97 | return registration; 98 | } 99 | 100 | @Bean 101 | // Defining a name allows us to use "omnissa.xxx" instead of "security.oauth2.xxx" in the application.yml file 102 | @ConfigurationProperties("omnissa") 103 | public ClientResources omnissa() { 104 | return new ClientResources(new OmnissaPrincipalExtractor()); 105 | } 106 | 107 | private Filter ssoFilter() { 108 | CompositeFilter filter = new CompositeFilter(); 109 | List filters = new ArrayList<>(); 110 | filters.add(ssoFilter(omnissa(), "/login/omnissa")); 111 | filter.setFilters(filters); 112 | return filter; 113 | } 114 | 115 | private Filter ssoFilter(ClientResources client, String path) { 116 | OAuth2ClientAuthenticationProcessingFilter oAuth2ClientAuthenticationFilter = new OAuth2ClientAuthenticationProcessingFilter( 117 | path); 118 | OAuth2RestTemplate oAuth2RestTemplate = new OAuth2RestTemplate(client.getClient(), oauth2ClientContext); 119 | oAuth2ClientAuthenticationFilter.setRestTemplate(oAuth2RestTemplate); 120 | UserInfoTokenServices tokenServices = new UserInfoTokenServices(client.getResource().getUserInfoUri(), 121 | client.getClient().getClientId()); 122 | tokenServices.setRestTemplate(oAuth2RestTemplate); 123 | tokenServices.setPrincipalExtractor(client.getPrincipalExtractor()); 124 | oAuth2ClientAuthenticationFilter.setTokenServices(tokenServices); 125 | return oAuth2ClientAuthenticationFilter; 126 | } 127 | 128 | } 129 | 130 | class ClientResources { 131 | 132 | @NestedConfigurationProperty 133 | private AuthorizationCodeResourceDetails client = new AuthorizationCodeResourceDetails(); 134 | 135 | @NestedConfigurationProperty 136 | private ResourceServerProperties resource = new ResourceServerProperties(); 137 | 138 | @NestedConfigurationProperty 139 | private PrincipalExtractor principalExtractor; 140 | 141 | public ClientResources(PrincipalExtractor principalExtractor) { 142 | this.principalExtractor = principalExtractor; 143 | } 144 | 145 | public AuthorizationCodeResourceDetails getClient() { 146 | return client; 147 | } 148 | 149 | public ResourceServerProperties getResource() { 150 | return resource; 151 | } 152 | 153 | public PrincipalExtractor getPrincipalExtractor() { 154 | return principalExtractor; 155 | } 156 | } 157 | 158 | class OmnissaPrincipalExtractor implements PrincipalExtractor { 159 | 160 | /** 161 | * Omnissa does not return any of the hard-coded keys, so use the custom 'subject' key to get some user info 162 | */ 163 | public static final String OMNISSA_KEY_SUBJECT = "subject"; 164 | 165 | @Override 166 | public Object extractPrincipal(Map map) { 167 | if (map.containsKey(OMNISSA_KEY_SUBJECT)) { 168 | return map.get(OMNISSA_KEY_SUBJECT); 169 | } 170 | return null; 171 | } 172 | } -------------------------------------------------------------------------------- /samples/DynamicRegistrationAppAuthDemo-Android/app/src/main/res/activity_token.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 15 | 16 | 25 | 26 | 32 | 33 | 39 | 40 | 46 |