Initial checkin
This commit is contained in:
Родитель
d31826b9e8
Коммит
2a665ce05b
|
@ -0,0 +1,50 @@
|
|||
*.doc diff=astextplain
|
||||
*.DOC diff=astextplain
|
||||
*.docx diff=astextplain
|
||||
*.DOCX diff=astextplain
|
||||
*.dot diff=astextplain
|
||||
*.DOT diff=astextplain
|
||||
*.pdf diff=astextplain
|
||||
*.PDF diff=astextplain
|
||||
*.rtf diff=astextplain
|
||||
*.RTF diff=astextplain
|
||||
|
||||
*.jpg binary
|
||||
*.png binary
|
||||
*.gif binary
|
||||
|
||||
*.cs text=auto diff=csharp
|
||||
*.vb text=auto
|
||||
*.resx text=auto
|
||||
*.c text=auto
|
||||
*.cpp text=auto
|
||||
*.cxx text=auto
|
||||
*.h text=auto
|
||||
*.hxx text=auto
|
||||
*.py text=auto
|
||||
*.rb text=auto
|
||||
*.java text=auto
|
||||
*.html text=auto
|
||||
*.htm text=auto
|
||||
*.css text=auto
|
||||
*.scss text=auto
|
||||
*.sass text=auto
|
||||
*.less text=auto
|
||||
*.js text=auto
|
||||
*.lisp text=auto
|
||||
*.clj text=auto
|
||||
*.sql text=auto
|
||||
*.php text=auto
|
||||
*.lua text=auto
|
||||
*.m text=auto
|
||||
*.asm text=auto
|
||||
*.erl text=auto
|
||||
*.fs text=auto
|
||||
*.fsx text=auto
|
||||
*.hs text=auto
|
||||
|
||||
*.csproj text=auto
|
||||
*.vbproj text=auto
|
||||
*.fsproj text=auto
|
||||
*.dbproj text=auto
|
||||
*.sln text=auto eol=crlf
|
|
@ -17,15 +17,13 @@
|
|||
[Rr]eleases/
|
||||
x64/
|
||||
x86/
|
||||
build/
|
||||
bld/
|
||||
[Bb]in/
|
||||
[Oo]bj/
|
||||
[Ll]og/
|
||||
|
||||
# Visual Studio 2015 cache/options directory
|
||||
# Visual Studo 2015 cache/options directory
|
||||
.vs/
|
||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
||||
#wwwroot/
|
||||
|
||||
# MSTest test Results
|
||||
[Tt]est[Rr]esult*/
|
||||
|
@ -40,10 +38,6 @@ TestResult.xml
|
|||
[Rr]eleasePS/
|
||||
dlldata.c
|
||||
|
||||
# DNX
|
||||
project.lock.json
|
||||
artifacts/
|
||||
|
||||
*_i.c
|
||||
*_p.c
|
||||
*_i.h
|
||||
|
@ -76,18 +70,14 @@ _Chutzpah*
|
|||
ipch/
|
||||
*.aps
|
||||
*.ncb
|
||||
*.opendb
|
||||
*.opensdf
|
||||
*.sdf
|
||||
*.cachefile
|
||||
*.VC.db
|
||||
*.VC.VC.opendb
|
||||
|
||||
# Visual Studio profiler
|
||||
*.psess
|
||||
*.vsp
|
||||
*.vspx
|
||||
*.sap
|
||||
|
||||
# TFS 2012 Local Workspace
|
||||
$tf/
|
||||
|
@ -100,7 +90,7 @@ _ReSharper*/
|
|||
*.[Rr]e[Ss]harper
|
||||
*.DotSettings.user
|
||||
|
||||
# JustCode is a .NET coding add-in
|
||||
# JustCode is a .NET coding addin-in
|
||||
.JustCode
|
||||
|
||||
# TeamCity is a build add-in
|
||||
|
@ -112,7 +102,6 @@ _TeamCity*
|
|||
# NCrunch
|
||||
_NCrunch_*
|
||||
.*crunch*.local.xml
|
||||
nCrunchTemp_*
|
||||
|
||||
# MightyMoose
|
||||
*.mm.*
|
||||
|
@ -140,16 +129,11 @@ publish/
|
|||
# Publish Web Output
|
||||
*.[Pp]ublish.xml
|
||||
*.azurePubxml
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# TODO: Comment the next line if you want to checkin your web deploy settings
|
||||
# but database connection strings (with potential passwords) will be unencrypted
|
||||
*.pubxml
|
||||
*.publishproj
|
||||
|
||||
# Microsoft Azure Web App publish settings. Comment the next line if you want to
|
||||
# checkin your Azure Web App publish settings, but sensitive information contained
|
||||
# in these scripts will be unencrypted
|
||||
PublishScripts/
|
||||
|
||||
# NuGet Packages
|
||||
*.nupkg
|
||||
# The packages folder can be ignored because of Package Restore
|
||||
|
@ -158,32 +142,18 @@ PublishScripts/
|
|||
!**/packages/build/
|
||||
# Uncomment if necessary however generally it will be regenerated when needed
|
||||
#!**/packages/repositories.config
|
||||
# NuGet v3's project.json files produces more ignoreable files
|
||||
*.nuget.props
|
||||
*.nuget.targets
|
||||
|
||||
# Microsoft Azure Build Output
|
||||
# Windows Azure Build Output
|
||||
csx/
|
||||
*.build.csdef
|
||||
|
||||
# Microsoft Azure Emulator
|
||||
ecf/
|
||||
rcf/
|
||||
|
||||
# Windows Store app package directories and files
|
||||
# Windows Store app package directory
|
||||
AppPackages/
|
||||
BundleArtifacts/
|
||||
Package.StoreAssociation.xml
|
||||
_pkginfo.txt
|
||||
|
||||
# Visual Studio cache files
|
||||
# files ending in .cache can be ignored
|
||||
*.[Cc]ache
|
||||
# but keep track of directories ending in .cache
|
||||
!*.[Cc]ache/
|
||||
|
||||
# Others
|
||||
*.[Cc]ache
|
||||
ClientBin/
|
||||
[Ss]tyle[Cc]op.*
|
||||
~$*
|
||||
*~
|
||||
*.dbmdl
|
||||
|
@ -191,11 +161,7 @@ ClientBin/
|
|||
*.pfx
|
||||
*.publishsettings
|
||||
node_modules/
|
||||
orleans.codegen.cs
|
||||
|
||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
||||
#bower_components/
|
||||
bower_components/
|
||||
|
||||
# RIA/Silverlight projects
|
||||
Generated_Code/
|
||||
|
@ -220,9 +186,6 @@ UpgradeLog*.htm
|
|||
# Microsoft Fakes
|
||||
FakesAssemblies/
|
||||
|
||||
# GhostDoc plugin setting file
|
||||
*.GhostDoc.xml
|
||||
|
||||
# Node.js Tools for Visual Studio
|
||||
.ntvs_analysis.dat
|
||||
|
||||
|
@ -232,21 +195,6 @@ FakesAssemblies/
|
|||
# Visual Studio 6 workspace options file
|
||||
*.opt
|
||||
|
||||
# Visual Studio LightSwitch build output
|
||||
**/*.HTMLClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/GeneratedArtifacts
|
||||
**/*.DesktopClient/ModelManifest.xml
|
||||
**/*.Server/GeneratedArtifacts
|
||||
**/*.Server/ModelManifest.xml
|
||||
_Pvt_Extensions
|
||||
# DNX-based projects have a project.lock.json file. This should not be checked-in during development
|
||||
project.lock.json
|
||||
|
||||
# Paket dependency manager
|
||||
.paket/paket.exe
|
||||
paket-files/
|
||||
|
||||
# FAKE - F# Make
|
||||
.fake/
|
||||
|
||||
# JetBrains Rider
|
||||
.idea/
|
||||
*.sln.iml
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
language: node_js
|
||||
sudo: required
|
||||
dist: trusty
|
||||
addons:
|
||||
apt:
|
||||
packages:
|
||||
- gettext
|
||||
- unzip
|
||||
- curl
|
||||
- libcurl4-openssl-dev
|
||||
- libicu-dev
|
||||
- libssl-dev
|
||||
- libunwind8
|
||||
- uuid-dev
|
||||
- zlib1g
|
||||
os:
|
||||
- linux
|
||||
- osx
|
||||
osx_image: xcode7.3
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- dev
|
||||
script:
|
||||
- ./scripts/travis_install.sh
|
||||
- ./scripts/travis_build.sh
|
||||
- ./scripts/travis_test.sh
|
|
@ -0,0 +1,202 @@
|
|||
|
||||
Apache License
|
||||
Version 2.0, January 2004
|
||||
http://www.apache.org/licenses/
|
||||
|
||||
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
|
||||
|
||||
1. Definitions.
|
||||
|
||||
"License" shall mean the terms and conditions for use, reproduction,
|
||||
and distribution as defined by Sections 1 through 9 of this document.
|
||||
|
||||
"Licensor" shall mean the copyright owner or entity authorized by
|
||||
the copyright owner that is granting the License.
|
||||
|
||||
"Legal Entity" shall mean the union of the acting entity and all
|
||||
other entities that control, are controlled by, or are under common
|
||||
control with that entity. For the purposes of this definition,
|
||||
"control" means (i) the power, direct or indirect, to cause the
|
||||
direction or management of such entity, whether by contract or
|
||||
otherwise, or (ii) ownership of fifty percent (50%) or more of the
|
||||
outstanding shares, or (iii) beneficial ownership of such entity.
|
||||
|
||||
"You" (or "Your") shall mean an individual or Legal Entity
|
||||
exercising permissions granted by this License.
|
||||
|
||||
"Source" form shall mean the preferred form for making modifications,
|
||||
including but not limited to software source code, documentation
|
||||
source, and configuration files.
|
||||
|
||||
"Object" form shall mean any form resulting from mechanical
|
||||
transformation or translation of a Source form, including but
|
||||
not limited to compiled object code, generated documentation,
|
||||
and conversions to other media types.
|
||||
|
||||
"Work" shall mean the work of authorship, whether in Source or
|
||||
Object form, made available under the License, as indicated by a
|
||||
copyright notice that is included in or attached to the work
|
||||
(an example is provided in the Appendix below).
|
||||
|
||||
"Derivative Works" shall mean any work, whether in Source or Object
|
||||
form, that is based on (or derived from) the Work and for which the
|
||||
editorial revisions, annotations, elaborations, or other modifications
|
||||
represent, as a whole, an original work of authorship. For the purposes
|
||||
of this License, Derivative Works shall not include works that remain
|
||||
separable from, or merely link (or bind by name) to the interfaces of,
|
||||
the Work and Derivative Works thereof.
|
||||
|
||||
"Contribution" shall mean any work of authorship, including
|
||||
the original version of the Work and any modifications or additions
|
||||
to that Work or Derivative Works thereof, that is intentionally
|
||||
submitted to Licensor for inclusion in the Work by the copyright owner
|
||||
or by an individual or Legal Entity authorized to submit on behalf of
|
||||
the copyright owner. For the purposes of this definition, "submitted"
|
||||
means any form of electronic, verbal, or written communication sent
|
||||
to the Licensor or its representatives, including but not limited to
|
||||
communication on electronic mailing lists, source code control systems,
|
||||
and issue tracking systems that are managed by, or on behalf of, the
|
||||
Licensor for the purpose of discussing and improving the Work, but
|
||||
excluding communication that is conspicuously marked or otherwise
|
||||
designated in writing by the copyright owner as "Not a Contribution."
|
||||
|
||||
"Contributor" shall mean Licensor and any individual or Legal Entity
|
||||
on behalf of whom a Contribution has been received by Licensor and
|
||||
subsequently incorporated within the Work.
|
||||
|
||||
2. Grant of Copyright License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
copyright license to reproduce, prepare Derivative Works of,
|
||||
publicly display, publicly perform, sublicense, and distribute the
|
||||
Work and such Derivative Works in Source or Object form.
|
||||
|
||||
3. Grant of Patent License. Subject to the terms and conditions of
|
||||
this License, each Contributor hereby grants to You a perpetual,
|
||||
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
|
||||
(except as stated in this section) patent license to make, have made,
|
||||
use, offer to sell, sell, import, and otherwise transfer the Work,
|
||||
where such license applies only to those patent claims licensable
|
||||
by such Contributor that are necessarily infringed by their
|
||||
Contribution(s) alone or by combination of their Contribution(s)
|
||||
with the Work to which such Contribution(s) was submitted. If You
|
||||
institute patent litigation against any entity (including a
|
||||
cross-claim or counterclaim in a lawsuit) alleging that the Work
|
||||
or a Contribution incorporated within the Work constitutes direct
|
||||
or contributory patent infringement, then any patent licenses
|
||||
granted to You under this License for that Work shall terminate
|
||||
as of the date such litigation is filed.
|
||||
|
||||
4. Redistribution. You may reproduce and distribute copies of the
|
||||
Work or Derivative Works thereof in any medium, with or without
|
||||
modifications, and in Source or Object form, provided that You
|
||||
meet the following conditions:
|
||||
|
||||
(a) You must give any other recipients of the Work or
|
||||
Derivative Works a copy of this License; and
|
||||
|
||||
(b) You must cause any modified files to carry prominent notices
|
||||
stating that You changed the files; and
|
||||
|
||||
(c) You must retain, in the Source form of any Derivative Works
|
||||
that You distribute, all copyright, patent, trademark, and
|
||||
attribution notices from the Source form of the Work,
|
||||
excluding those notices that do not pertain to any part of
|
||||
the Derivative Works; and
|
||||
|
||||
(d) If the Work includes a "NOTICE" text file as part of its
|
||||
distribution, then any Derivative Works that You distribute must
|
||||
include a readable copy of the attribution notices contained
|
||||
within such NOTICE file, excluding those notices that do not
|
||||
pertain to any part of the Derivative Works, in at least one
|
||||
of the following places: within a NOTICE text file distributed
|
||||
as part of the Derivative Works; within the Source form or
|
||||
documentation, if provided along with the Derivative Works; or,
|
||||
within a display generated by the Derivative Works, if and
|
||||
wherever such third-party notices normally appear. The contents
|
||||
of the NOTICE file are for informational purposes only and
|
||||
do not modify the License. You may add Your own attribution
|
||||
notices within Derivative Works that You distribute, alongside
|
||||
or as an addendum to the NOTICE text from the Work, provided
|
||||
that such additional attribution notices cannot be construed
|
||||
as modifying the License.
|
||||
|
||||
You may add Your own copyright statement to Your modifications and
|
||||
may provide additional or different license terms and conditions
|
||||
for use, reproduction, or distribution of Your modifications, or
|
||||
for any such Derivative Works as a whole, provided Your use,
|
||||
reproduction, and distribution of the Work otherwise complies with
|
||||
the conditions stated in this License.
|
||||
|
||||
5. Submission of Contributions. Unless You explicitly state otherwise,
|
||||
any Contribution intentionally submitted for inclusion in the Work
|
||||
by You to the Licensor shall be under the terms and conditions of
|
||||
this License, without any additional terms or conditions.
|
||||
Notwithstanding the above, nothing herein shall supersede or modify
|
||||
the terms of any separate license agreement you may have executed
|
||||
with Licensor regarding such Contributions.
|
||||
|
||||
6. Trademarks. This License does not grant permission to use the trade
|
||||
names, trademarks, service marks, or product names of the Licensor,
|
||||
except as required for reasonable and customary use in describing the
|
||||
origin of the Work and reproducing the content of the NOTICE file.
|
||||
|
||||
7. Disclaimer of Warranty. Unless required by applicable law or
|
||||
agreed to in writing, Licensor provides the Work (and each
|
||||
Contributor provides its Contributions) on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
|
||||
implied, including, without limitation, any warranties or conditions
|
||||
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
|
||||
PARTICULAR PURPOSE. You are solely responsible for determining the
|
||||
appropriateness of using or redistributing the Work and assume any
|
||||
risks associated with Your exercise of permissions under this License.
|
||||
|
||||
8. Limitation of Liability. In no event and under no legal theory,
|
||||
whether in tort (including negligence), contract, or otherwise,
|
||||
unless required by applicable law (such as deliberate and grossly
|
||||
negligent acts) or agreed to in writing, shall any Contributor be
|
||||
liable to You for damages, including any direct, indirect, special,
|
||||
incidental, or consequential damages of any character arising as a
|
||||
result of this License or out of the use or inability to use the
|
||||
Work (including but not limited to damages for loss of goodwill,
|
||||
work stoppage, computer failure or malfunction, or any and all
|
||||
other commercial damages or losses), even if such Contributor
|
||||
has been advised of the possibility of such damages.
|
||||
|
||||
9. Accepting Warranty or Additional Liability. While redistributing
|
||||
the Work or Derivative Works thereof, You may choose to offer,
|
||||
and charge a fee for, acceptance of support, warranty, indemnity,
|
||||
or other liability obligations and/or rights consistent with this
|
||||
License. However, in accepting such obligations, You may act only
|
||||
on Your own behalf and on Your sole responsibility, not on behalf
|
||||
of any other Contributor, and only if You agree to indemnify,
|
||||
defend, and hold each Contributor harmless for any liability
|
||||
incurred by, or claims asserted against, such Contributor by reason
|
||||
of your accepting any such warranty or additional liability.
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
APPENDIX: How to apply the Apache License to your work.
|
||||
|
||||
To apply the Apache License to your work, attach the following
|
||||
boilerplate notice, with the fields enclosed by brackets "[]"
|
||||
replaced with your own identifying information. (Don't include
|
||||
the brackets!) The text should be enclosed in the appropriate
|
||||
comment syntax for the file format. We also recommend that a
|
||||
file or class name and description of purpose be included on the
|
||||
same "printed page" as the copyright notice for easier
|
||||
identification within third-party archives.
|
||||
|
||||
Copyright [yyyy] [name of copyright owner]
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
|
@ -0,0 +1,41 @@
|
|||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio 14
|
||||
VisualStudioVersion = 14.0.25420.1
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{5804915A-5476-4DE7-AFDD-4492F37543D3}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "test", "test", "{5CB4DFCB-2083-4EF9-8C62-ECC7A9DF2F9B}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SteelToe.Security.Authentication.CloudFoundry", "src\SteelToe.Security.Authentication.CloudFoundry\SteelToe.Security.Authentication.CloudFoundry.xproj", "{CC60F638-A791-4694-998C-2B1559D37207}"
|
||||
EndProject
|
||||
Project("{8BB2217D-0F2D-49D1-97BC-3654ED321F3B}") = "SteelToe.Security.Authentication.CloudFoundry.Test", "test\SteelToe.Security.Authentication.CloudFoundry.Test\SteelToe.Security.Authentication.CloudFoundry.Test.xproj", "{0B258F76-09D9-44FE-8232-CBF33F68242C}"
|
||||
EndProject
|
||||
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{CC82EA8F-5967-43DF-950E-309E52603A6E}"
|
||||
ProjectSection(SolutionItems) = preProject
|
||||
global.json = global.json
|
||||
EndProjectSection
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{CC60F638-A791-4694-998C-2B1559D37207}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{CC60F638-A791-4694-998C-2B1559D37207}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{CC60F638-A791-4694-998C-2B1559D37207}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{CC60F638-A791-4694-998C-2B1559D37207}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
{0B258F76-09D9-44FE-8232-CBF33F68242C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0B258F76-09D9-44FE-8232-CBF33F68242C}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0B258F76-09D9-44FE-8232-CBF33F68242C}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0B258F76-09D9-44FE-8232-CBF33F68242C}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
GlobalSection(NestedProjects) = preSolution
|
||||
{CC60F638-A791-4694-998C-2B1559D37207} = {5804915A-5476-4DE7-AFDD-4492F37543D3}
|
||||
{0B258F76-09D9-44FE-8232-CBF33F68242C} = {5CB4DFCB-2083-4EF9-8C62-ECC7A9DF2F9B}
|
||||
EndGlobalSection
|
||||
EndGlobal
|
|
@ -0,0 +1,42 @@
|
|||
version: '1.0.0-{branch}-{build}'
|
||||
init:
|
||||
- git config --global core.autocrlf true
|
||||
branches:
|
||||
only:
|
||||
- master
|
||||
- dev
|
||||
install:
|
||||
- scripts\appveyor_install.cmd
|
||||
test_script:
|
||||
- scripts\appveyor_tests.cmd
|
||||
build_script:
|
||||
- scripts\appveyor_build.cmd
|
||||
artifacts:
|
||||
- path: 'src\SteelToe.Security.Authentication.CloudFoundry\bin\Release\*.nupkg'
|
||||
deploy:
|
||||
- provider: NuGet
|
||||
skip_symbols: true
|
||||
artifact: /.*\.nupkg/
|
||||
server: https://www.myget.org/F/steeltoemaster/api/v2/package
|
||||
api_key:
|
||||
secure: 246ApObnMYYvzDo9Ki72CxxuKfuoqYbrbUK2HLevGIGHXYY6f0OkAdE3EWCwNJ7g
|
||||
on:
|
||||
branch: master
|
||||
appveyor_repo_tag: false
|
||||
- provider: NuGet
|
||||
skip_symbols: true
|
||||
artifact: /.*\.nupkg/
|
||||
server: https://www.myget.org/F/steeltoedev/api/v2/package
|
||||
api_key:
|
||||
secure: 246ApObnMYYvzDo9Ki72CxxuKfuoqYbrbUK2HLevGIGHXYY6f0OkAdE3EWCwNJ7g
|
||||
on:
|
||||
branch: dev
|
||||
appveyor_repo_tag: false
|
||||
- provider: NuGet
|
||||
skip_symbols: true
|
||||
artifact: /.*\.nupkg/
|
||||
api_key:
|
||||
secure: RGkpu8xIMDC75IAd1qPRdueeTaYj+ddW2bNEw8S7e81940ELu+WV04uWAzqV34/C
|
||||
on:
|
||||
branch: master
|
||||
appveyor_repo_tag: true
|
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"projects": [ "src", "test" ],
|
||||
"sdk": {
|
||||
"version": "1.0.0-preview2-003121"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,8 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<configuration>
|
||||
<packageSources>
|
||||
<add key="SteelToeMaster" value="https://www.myget.org/F/steeltoemaster/api/v3/index.json" />
|
||||
<add key="SteelToeDev" value="https://www.myget.org/F/steeltoedev/api/v3/index.json" />
|
||||
<add key="NuGet" value="https://api.nuget.org/v3/index.json" />
|
||||
</packageSources>
|
||||
</configuration>
|
|
@ -0,0 +1,20 @@
|
|||
:: @ECHO OFF
|
||||
|
||||
:: Patch project.json files
|
||||
cd %APPVEYOR_BUILD_FOLDER%\scripts
|
||||
call npm install
|
||||
call node patch-project-json.js ../src/SteelToe.Security.Authentication.CloudFoundry/project.json %APPVEYOR_BUILD_VERSION% %APPVEYOR_REPO_TAG_NAME%
|
||||
cd %APPVEYOR_BUILD_FOLDER%
|
||||
|
||||
:: Restore packages
|
||||
cd src
|
||||
dotnet restore
|
||||
cd ..\test
|
||||
dotnet restore
|
||||
cd ..
|
||||
|
||||
:: Build packages
|
||||
cd src\SteelToe.Security.Authentication.CloudFoundry
|
||||
dotnet pack --configuration Release
|
||||
cd %APPVEYOR_BUILD_FOLDER%
|
||||
|
|
@ -0,0 +1,5 @@
|
|||
@ECHO OFF
|
||||
:: Output dotnet info
|
||||
dotnet --info
|
||||
:: For patching project.json's
|
||||
call npm install jsonfile -g
|
|
@ -0,0 +1,6 @@
|
|||
@ECHO OFF
|
||||
|
||||
:: Run unit tests
|
||||
cd test\SteelToe.Security.Authentication.CloudFoundry.Test
|
||||
dotnet test
|
||||
cd ..\..
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"name": "patch-project-json",
|
||||
"version": "0.0.2",
|
||||
"private": true,
|
||||
"description": "Patches the version number on .NET Core project.json files",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": ""
|
||||
},
|
||||
"main": "patch-project-json.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"dependencies": {
|
||||
"jsonfile": "^2.2.3"
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
var jsonfile = require('jsonfile');
|
||||
|
||||
// Read in the file to be patched
|
||||
var file = process.argv[2]; // e.g. '../src/MyProject/project.json'
|
||||
if (!file)
|
||||
console.log("No filename provided");
|
||||
console.log("File: " + file);
|
||||
|
||||
// Read in the build version (this is provided by the CI server)
|
||||
var version = process.argv[3]; // e.g. '1.0.0-master-10'
|
||||
var tag = process.argv[4]; // e.g. '', or '1.0.0-rc1'
|
||||
|
||||
if (!version)
|
||||
console.log("No version provided");
|
||||
|
||||
var lastDash = version.lastIndexOf("-");
|
||||
var buildNumber = version.substring(lastDash + 1, version.length);
|
||||
var num = "00000000" + parseInt(buildNumber);
|
||||
buildNumber = num.substr(num.length-5);
|
||||
|
||||
var dependsVersion = version.substring(0, lastDash) + '-*';
|
||||
|
||||
if (tag) {
|
||||
// Turn version into tag + '-' + buildnumber
|
||||
version = tag + '-' + buildNumber;
|
||||
} else {
|
||||
version = version.substring(0, lastDash) + '-' + buildNumber;
|
||||
}
|
||||
|
||||
jsonfile.readFile(file, function (err, project) {
|
||||
|
||||
console.log("Version: " + version);
|
||||
|
||||
// Patch the project.version
|
||||
project.version = version;
|
||||
|
||||
// Patch dependencies
|
||||
project.dependencies['SteelToe.CloudFoundry.Connector.OAuth'] = dependsVersion;
|
||||
|
||||
jsonfile.writeFile(file, project, {spaces: 2}, function(err) {
|
||||
if (err)
|
||||
console.error(err);
|
||||
});
|
||||
})
|
|
@ -0,0 +1,18 @@
|
|||
#!/bin/bash
|
||||
export STEELTOE_VERSION="1.0.0"
|
||||
export DOTNET_INSTALL_DIR="$PWD/.dotnetsdk"
|
||||
export PATH="$DOTNET_INSTALL_DIR:$PATH"
|
||||
# Patch project.json files
|
||||
cd ./scripts
|
||||
npm install
|
||||
node patch-project-json.js ../src/SteelToe.Security.Authentication.CloudFoundry/project.json $STEELTOE_VERSION-$TRAVIS_BRANCH-$TRAVIS_BUILD_NUMBER $TRAVIS_TAG
|
||||
cd ..
|
||||
cd src
|
||||
dotnet restore
|
||||
cd ../test
|
||||
dotnet restore
|
||||
cd ..
|
||||
cd src/SteelToe.Security.Authentication.CloudFoundry
|
||||
dotnet build --framework netstandard1.3 --configuration Release
|
||||
cd ../..
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
#!/bin/bash
|
||||
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew update ; fi
|
||||
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then brew install openssl ; fi
|
||||
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ln -s /usr/local/opt/openssl/lib/libcrypto.1.0.0.dylib /usr/local/lib/ ; fi
|
||||
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then ln -s /usr/local/opt/openssl/lib/libssl.1.0.0.dylib /usr/local/lib/ ; fi
|
||||
if [[ "$TRAVIS_OS_NAME" == "osx" ]]; then export DOTNET_SDK_URL=https://go.microsoft.com/fwlink/?LinkID=809128 ; fi
|
||||
if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then export DOTNET_SDK_URL=https://go.microsoft.com/fwlink/?LinkID=809129 ; fi
|
||||
export DOTNET_INSTALL_DIR="$PWD/.dotnetsdk"
|
||||
mkdir -p "$DOTNET_INSTALL_DIR"
|
||||
curl -L "$DOTNET_SDK_URL" | tar -xzv -C "$DOTNET_INSTALL_DIR"
|
||||
export PATH="$DOTNET_INSTALL_DIR:$PATH"
|
||||
dotnet --info
|
||||
npm install jsonfile -g
|
|
@ -0,0 +1,9 @@
|
|||
#!/bin/bash
|
||||
export DOTNET_INSTALL_DIR="$PWD/.dotnetsdk"
|
||||
export PATH="$DOTNET_INSTALL_DIR:$PATH"
|
||||
# Run unit tests
|
||||
cd test/SteelToe.Security.Authentication.CloudFoundry.Test
|
||||
dotnet test --framework netcoreapp1.0
|
||||
cd ../..
|
||||
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
//
|
||||
// Copyright 2015 the original author or authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
using System;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.Extensions.Options;
|
||||
using SteelToe.CloudFoundry.Connector.OAuth;
|
||||
|
||||
namespace SteelToe.Security.Authentication.CloudFoundry
|
||||
{
|
||||
|
||||
public static class CloudFoundryAppBuilderExtensions
|
||||
{
|
||||
public static IApplicationBuilder UseCloudFoundryAuthentication(this IApplicationBuilder builder )
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
|
||||
var iopts = builder.ApplicationServices.GetService(typeof(IOptions<OAuthServiceOptions>)) as IOptions<OAuthServiceOptions>;
|
||||
var signonOpts = iopts?.Value;
|
||||
|
||||
CloudFoundryOptions cloudOpts = null;
|
||||
if (signonOpts != null)
|
||||
{
|
||||
cloudOpts = new CloudFoundryOptions(signonOpts);
|
||||
} else
|
||||
{
|
||||
cloudOpts = new CloudFoundryOptions();
|
||||
}
|
||||
|
||||
|
||||
return builder.UseMiddleware<CloudFoundryMiddleware>(Options.Create(cloudOpts));
|
||||
}
|
||||
|
||||
public static IApplicationBuilder UseCloudFoundryAuthentication(this IApplicationBuilder builder, CloudFoundryOptions options)
|
||||
{
|
||||
if (builder == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(builder));
|
||||
}
|
||||
if (options == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
}
|
||||
|
||||
return builder.UseMiddleware<CloudFoundryMiddleware>(Options.Create(options));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,271 @@
|
|||
//
|
||||
// Copyright 2015 the original author or authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||
using Microsoft.AspNetCore.Http.Authentication;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Security.Claims;
|
||||
using System.Threading.Tasks;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using Microsoft.AspNetCore.WebUtilities;
|
||||
using System.Net.Http.Headers;
|
||||
using System.Net.Security;
|
||||
using System.Net;
|
||||
using System.Text;
|
||||
|
||||
|
||||
namespace SteelToe.Security.Authentication.CloudFoundry
|
||||
{
|
||||
internal class CloudFoundryHandler : OAuthHandler<CloudFoundryOptions>
|
||||
{
|
||||
public CloudFoundryHandler(HttpClient httpClient)
|
||||
: base(httpClient)
|
||||
{
|
||||
}
|
||||
|
||||
protected override async Task<OAuthTokenResponse> ExchangeCodeAsync(string code, string redirectUri)
|
||||
{
|
||||
|
||||
HttpRequestMessage requestMessage = GetTokenRequestMessage(code, redirectUri);
|
||||
HttpClient client = GetHttpClient();
|
||||
#if NET451
|
||||
RemoteCertificateValidationCallback prevValidator = null;
|
||||
if (!Options.ValidateCertificates)
|
||||
{
|
||||
prevValidator = ServicePointManager.ServerCertificateValidationCallback;
|
||||
ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;
|
||||
}
|
||||
#endif
|
||||
HttpResponseMessage response = null;
|
||||
try
|
||||
{
|
||||
response = await client.SendAsync(requestMessage, Context.RequestAborted);
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if NET451
|
||||
ServicePointManager.ServerCertificateValidationCallback = prevValidator;
|
||||
#endif
|
||||
}
|
||||
|
||||
if (response.IsSuccessStatusCode)
|
||||
{
|
||||
var result = await response.Content.ReadAsStringAsync();
|
||||
var payload = JObject.Parse(result);
|
||||
return OAuthTokenResponse.Success(payload);
|
||||
}
|
||||
else
|
||||
{
|
||||
var error = "OAuth token endpoint failure: " + await Display(response);
|
||||
return OAuthTokenResponse.Failed(new Exception(error));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected override async Task<AuthenticationTicket> CreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)
|
||||
{
|
||||
|
||||
HttpRequestMessage request = GetTokenInfoRequestMessage(tokens);
|
||||
HttpClient client = GetHttpClient();
|
||||
|
||||
#if NET451
|
||||
RemoteCertificateValidationCallback prevValidator = null;
|
||||
if (!Options.ValidateCertificates)
|
||||
{
|
||||
prevValidator = ServicePointManager.ServerCertificateValidationCallback;
|
||||
ServicePointManager.ServerCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;
|
||||
}
|
||||
#endif
|
||||
|
||||
HttpResponseMessage response = null;
|
||||
try
|
||||
{
|
||||
response = await client.SendAsync(request, Context.RequestAborted);
|
||||
}
|
||||
finally
|
||||
{
|
||||
#if NET451
|
||||
ServicePointManager.ServerCertificateValidationCallback = prevValidator;
|
||||
#endif
|
||||
}
|
||||
|
||||
response.EnsureSuccessStatusCode();
|
||||
|
||||
var resp = await response.Content.ReadAsStringAsync();
|
||||
var payload = JObject.Parse(resp);
|
||||
|
||||
var identifier = CloudFoundryHelper.GetId(payload);
|
||||
if (!string.IsNullOrEmpty(identifier))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, identifier, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var givenName = CloudFoundryHelper.GetGivenName(payload);
|
||||
if (!string.IsNullOrEmpty(givenName))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.GivenName, givenName, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var familyName = CloudFoundryHelper.GetFamilyName(payload);
|
||||
if (!string.IsNullOrEmpty(familyName))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Surname, familyName, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var name = CloudFoundryHelper.GetName(payload);
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Name, name, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var email = CloudFoundryHelper.GetEmail(payload);
|
||||
if (!string.IsNullOrEmpty(email))
|
||||
{
|
||||
identity.AddClaim(new Claim(ClaimTypes.Email, email, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
|
||||
var scopes = CloudFoundryHelper.GetScopes(payload);
|
||||
if (scopes != null)
|
||||
{
|
||||
foreach (var s in scopes)
|
||||
{
|
||||
identity.AddClaim(new Claim(s, string.Empty, ClaimValueTypes.String, Options.ClaimsIssuer));
|
||||
}
|
||||
}
|
||||
|
||||
var ticket = new AuthenticationTicket(new ClaimsPrincipal(identity), properties, Options.AuthenticationScheme);
|
||||
var context = new OAuthCreatingTicketContext(ticket, Context, Options, Backchannel, tokens, payload);
|
||||
|
||||
await Options.Events.CreatingTicket(context);
|
||||
|
||||
return context.Ticket;
|
||||
}
|
||||
|
||||
|
||||
protected override string BuildChallengeUrl(AuthenticationProperties properties, string redirectUri)
|
||||
{
|
||||
var scope = FormatScope();
|
||||
|
||||
var queryStrings = new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
|
||||
queryStrings.Add("response_type", "code");
|
||||
queryStrings.Add("client_id", Options.ClientId);
|
||||
queryStrings.Add("redirect_uri", redirectUri);
|
||||
|
||||
AddQueryString(queryStrings, properties, "scope", scope);
|
||||
|
||||
if (Options.StateDataFormat != null)
|
||||
{
|
||||
var state = Options.StateDataFormat.Protect(properties);
|
||||
queryStrings.Add("state", state);
|
||||
}
|
||||
|
||||
var authorizationEndpoint = QueryHelpers.AddQueryString(Options.AuthorizationEndpoint, queryStrings);
|
||||
return authorizationEndpoint;
|
||||
}
|
||||
|
||||
internal protected virtual Dictionary<string, string> GetTokenInfoRequestParameters(OAuthTokenResponse tokens)
|
||||
{
|
||||
return new Dictionary<string, string>()
|
||||
{
|
||||
{ "token", tokens.AccessToken }
|
||||
|
||||
};
|
||||
}
|
||||
|
||||
internal protected virtual HttpRequestMessage GetTokenInfoRequestMessage(OAuthTokenResponse tokens)
|
||||
{
|
||||
var tokenRequestParameters = GetTokenInfoRequestParameters(tokens);
|
||||
|
||||
var requestContent = new FormUrlEncodedContent(tokenRequestParameters);
|
||||
var request = new HttpRequestMessage(HttpMethod.Post, Options.TokenInfoUrl);
|
||||
request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
request.Headers.Authorization = new AuthenticationHeaderValue("Basic", GetEncoded(Options.ClientId, Options.ClientSecret));
|
||||
request.Content = requestContent;
|
||||
return request;
|
||||
}
|
||||
|
||||
internal protected virtual Dictionary<string, string> GetTokenRequestParameters(string code, string redirectUri)
|
||||
{
|
||||
return new Dictionary<string, string>()
|
||||
{
|
||||
{ "client_id", Options.ClientId },
|
||||
{ "redirect_uri", redirectUri },
|
||||
{ "client_secret", Options.ClientSecret },
|
||||
{ "code", code },
|
||||
{ "grant_type", "authorization_code" },
|
||||
};
|
||||
}
|
||||
|
||||
internal protected virtual HttpRequestMessage GetTokenRequestMessage(string code, string redirectUri)
|
||||
{
|
||||
var tokenRequestParameters = GetTokenRequestParameters(code, redirectUri);
|
||||
|
||||
var requestContent = new FormUrlEncodedContent(tokenRequestParameters);
|
||||
|
||||
var requestMessage = new HttpRequestMessage(HttpMethod.Post, Options.TokenEndpoint);
|
||||
requestMessage.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
requestMessage.Content = requestContent;
|
||||
return requestMessage;
|
||||
}
|
||||
|
||||
internal protected string GetEncoded(string user, string password)
|
||||
{
|
||||
if (user == null)
|
||||
user = string.Empty;
|
||||
if (password == null)
|
||||
password = string.Empty;
|
||||
return Convert.ToBase64String(Encoding.ASCII.GetBytes(user + ":" + password));
|
||||
}
|
||||
|
||||
internal protected virtual HttpClient GetHttpClient()
|
||||
{
|
||||
return Backchannel;
|
||||
}
|
||||
|
||||
private static void AddQueryString(IDictionary<string, string> queryStrings, AuthenticationProperties properties, string name, string defaultValue = null)
|
||||
{
|
||||
string value;
|
||||
if (!properties.Items.TryGetValue(name, out value))
|
||||
{
|
||||
value = defaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
properties.Items.Remove(name);
|
||||
}
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
queryStrings[name] = value;
|
||||
}
|
||||
private static async Task<string> Display(HttpResponseMessage response)
|
||||
{
|
||||
var output = new StringBuilder();
|
||||
output.Append("Status: " + response.StatusCode + ";");
|
||||
output.Append("Headers: " + response.Headers.ToString() + ";");
|
||||
output.Append("Body: " + await response.Content.ReadAsStringAsync() + ";");
|
||||
return output.ToString();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,157 @@
|
|||
//
|
||||
// Copyright 2015 the original author or authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
using System;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace SteelToe.Security.Authentication.CloudFoundry
|
||||
{
|
||||
|
||||
public static class CloudFoundryHelper
|
||||
{
|
||||
|
||||
public static string GetId(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("user_id");
|
||||
}
|
||||
|
||||
public static string GetUserName(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("user_name");
|
||||
}
|
||||
|
||||
public static string GetName(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("user_name");
|
||||
}
|
||||
|
||||
public static string GetGivenName(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("given_name");
|
||||
}
|
||||
|
||||
public static string GetFamilyName(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("family_name");
|
||||
}
|
||||
|
||||
|
||||
public static string GetEmail(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
return user.Value<string>("email");
|
||||
}
|
||||
|
||||
public static List<string> GetScopes(JObject user)
|
||||
{
|
||||
if (user == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(user));
|
||||
}
|
||||
|
||||
List<string> result = new List<string>();
|
||||
var scopes = user["scope"];
|
||||
if (scopes == null)
|
||||
{
|
||||
return result;
|
||||
}
|
||||
|
||||
var asValue = scopes as JValue;
|
||||
if (asValue != null)
|
||||
{
|
||||
result.Add(asValue.Value<string>());
|
||||
return result;
|
||||
}
|
||||
var asArray = scopes as JArray;
|
||||
if (asArray != null)
|
||||
{
|
||||
foreach (string s in asArray)
|
||||
{
|
||||
result.Add(s);
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
// Get the given subProperty from a property.
|
||||
private static string TryGetValue(JObject user, string propertyName, string subProperty)
|
||||
{
|
||||
JToken value;
|
||||
if (user.TryGetValue(propertyName, out value))
|
||||
{
|
||||
var subObject = JObject.Parse(value.ToString());
|
||||
if (subObject != null && subObject.TryGetValue(subProperty, out value))
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
// Get the given subProperty from a list property.
|
||||
private static string TryGetFirstValue(JObject user, string propertyName, string subProperty)
|
||||
{
|
||||
JToken value;
|
||||
if (user.TryGetValue(propertyName, out value))
|
||||
{
|
||||
var array = JArray.Parse(value.ToString());
|
||||
if (array != null && array.Count > 0)
|
||||
{
|
||||
var subObject = JObject.Parse(array.First.ToString());
|
||||
if (subObject != null)
|
||||
{
|
||||
if (subObject.TryGetValue(subProperty, out value))
|
||||
{
|
||||
return value.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
|
||||
//
|
||||
// Copyright 2015 the original author or authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||
using Microsoft.AspNetCore.DataProtection;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
using Microsoft.Extensions.Options;
|
||||
using System.Text.Encodings.Web;
|
||||
|
||||
namespace SteelToe.Security.Authentication.CloudFoundry
|
||||
{
|
||||
|
||||
public class CloudFoundryMiddleware : OAuthMiddleware<CloudFoundryOptions>
|
||||
{
|
||||
|
||||
public CloudFoundryMiddleware(
|
||||
RequestDelegate next,
|
||||
IDataProtectionProvider dataProtectionProvider,
|
||||
ILoggerFactory loggerFactory,
|
||||
UrlEncoder encoder,
|
||||
IOptions<SharedAuthenticationOptions> sharedOptions,
|
||||
IOptions<CloudFoundryOptions> options)
|
||||
: base(next, dataProtectionProvider, loggerFactory, encoder, sharedOptions, options)
|
||||
{
|
||||
}
|
||||
|
||||
protected override AuthenticationHandler<CloudFoundryOptions> CreateHandler()
|
||||
{
|
||||
return new CloudFoundryHandler(Backchannel);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
//
|
||||
// Copyright 2015 the original author or authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
using System.Net.Http;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using SteelToe.CloudFoundry.Connector.OAuth;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
|
||||
namespace SteelToe.Security.Authentication.CloudFoundry
|
||||
{
|
||||
|
||||
public class CloudFoundryOptions : OAuthOptions
|
||||
{
|
||||
internal const string Default_AuthorizationUri = "/oauth/authorize";
|
||||
internal const string Default_AccessTokenUri = "/oauth/token";
|
||||
internal const string Default_UserInfoUri = "/userinfo";
|
||||
internal const string Default_CheckTokenUri = "/check_token";
|
||||
internal const string Default_JwtTokenKey = "/token_key";
|
||||
internal const string Default_OAuthServiceUrl = "Default_OAuthServiceUrl";
|
||||
internal const string Default_ClientId = "Default_ClientId";
|
||||
internal const string Default_ClientSecret = "Default_ClientSecret";
|
||||
|
||||
public const string AUTHENTICATION_SCHEME = "CloudFoundry";
|
||||
public string TokenInfoUrl { get; set; }
|
||||
public string JwtKeyUrl { get; set; }
|
||||
public bool ValidateCertificates { get; set; } = true;
|
||||
|
||||
public CloudFoundryOptions()
|
||||
{
|
||||
string authURL = "http://" + Default_OAuthServiceUrl;
|
||||
ClaimsIssuer = AUTHENTICATION_SCHEME;
|
||||
ClientId = Default_ClientId;
|
||||
ClientSecret = Default_ClientSecret;
|
||||
AuthenticationScheme = CloudFoundryOptions.AUTHENTICATION_SCHEME;
|
||||
DisplayName = CloudFoundryOptions.AUTHENTICATION_SCHEME;
|
||||
CallbackPath = new PathString("/signin-cloudfoundry");
|
||||
AuthorizationEndpoint = authURL + Default_AuthorizationUri;
|
||||
TokenEndpoint = authURL + Default_AccessTokenUri;
|
||||
UserInformationEndpoint = authURL + Default_UserInfoUri;
|
||||
TokenInfoUrl = authURL + Default_CheckTokenUri;
|
||||
JwtKeyUrl = authURL + Default_JwtTokenKey;
|
||||
Scope.Clear();
|
||||
BackchannelHttpHandler = GetBackChannelHandler();
|
||||
}
|
||||
|
||||
public CloudFoundryOptions(OAuthServiceOptions options)
|
||||
{
|
||||
ClaimsIssuer = AUTHENTICATION_SCHEME;
|
||||
ClientId = options.ClientId;
|
||||
ClientSecret = options.ClientSecret;
|
||||
AuthenticationScheme = CloudFoundryOptions.AUTHENTICATION_SCHEME;
|
||||
DisplayName = CloudFoundryOptions.AUTHENTICATION_SCHEME;
|
||||
CallbackPath = new PathString("/signin-cloudfoundry");
|
||||
AuthorizationEndpoint = options.UserAuthorizationUrl;
|
||||
TokenEndpoint = options.AccessTokenUrl;
|
||||
UserInformationEndpoint = options.UserInfoUrl;
|
||||
TokenInfoUrl = options.TokenInfoUrl;
|
||||
JwtKeyUrl = options.JwtKeyUrl;
|
||||
ValidateCertificates = options.ValidateCertificates;
|
||||
|
||||
foreach (var scope in options.Scope)
|
||||
{
|
||||
Scope.Add(scope);
|
||||
}
|
||||
|
||||
BackchannelHttpHandler = GetBackChannelHandler();
|
||||
}
|
||||
|
||||
internal protected virtual HttpMessageHandler GetBackChannelHandler()
|
||||
{
|
||||
#if NET451
|
||||
return null;
|
||||
#else
|
||||
if (!ValidateCertificates && RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
|
||||
{
|
||||
var handler = new WinHttpHandler();
|
||||
handler.ServerCertificateValidationCallback = (sender, cert, chain, sslPolicyErrors) => true;
|
||||
return handler;
|
||||
}
|
||||
return null;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,21 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("SteelToe.Security.Authentication.CloudFoundry")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("cc60f638-a791-4694-998c-2b1559d37207")]
|
||||
|
||||
[assembly: InternalsVisibleTo("SteelToe.Security.Authentication.CloudFoundry.Test")]
|
|
@ -0,0 +1,21 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>cc60f638-a791-4694-998c-2b1559d37207</ProjectGuid>
|
||||
<RootNamespace>SteelToe.Security.Authentication.CloudFoundry</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
|
@ -0,0 +1,45 @@
|
|||
{
|
||||
"version": "1.0.0",
|
||||
"description": "ASP.NET Core External Security Provider for CloudFoundry",
|
||||
"authors": [
|
||||
"Pivotal",
|
||||
"dtillman"
|
||||
],
|
||||
"packOptions": {
|
||||
"tags": [
|
||||
"CloudFoundry",
|
||||
"ASPNET Core",
|
||||
"Security",
|
||||
"OAuth2",
|
||||
"Single Sign-On"
|
||||
],
|
||||
"projectUrl": "http://steeltoe.io",
|
||||
"licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0",
|
||||
"copyright": "Copyright 2016 the original authors"
|
||||
},
|
||||
"frameworks": {
|
||||
"net451": {
|
||||
"dependencies": {
|
||||
"System.Net.Http": "4.0.0"
|
||||
}
|
||||
},
|
||||
"netstandard1.3": {
|
||||
"imports": "dnxcore50",
|
||||
"dependencies": {
|
||||
"System.Net.Http.WinHttpHandler": "4.0.0",
|
||||
"System.Threading.Thread": "4.0.0"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"System.Runtime.InteropServices.RuntimeInformation": "4.0.0-*",
|
||||
"Microsoft.AspNetCore.Authentication": "1.0.0",
|
||||
"Microsoft.AspNetCore.Authentication.Cookies": "1.0.0",
|
||||
"Microsoft.AspNetCore.Authentication.OAuth": "1.0.0",
|
||||
"Microsoft.AspNetCore.Authorization": "1.0.0",
|
||||
"Microsoft.AspNetCore.Http.Abstractions": "1.0.0",
|
||||
"Microsoft.Extensions.Options": "1.0.0",
|
||||
"SteelToe.CloudFoundry.Connector.OAuth": "1.0.0-*"
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,113 @@
|
|||
//
|
||||
// Copyright 2015 the original author or authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
using System;
|
||||
|
||||
using Microsoft.AspNetCore.Hosting;
|
||||
using Microsoft.AspNetCore.TestHost;
|
||||
using Xunit;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Builder.Internal;
|
||||
using SteelToe.CloudFoundry.Connector.OAuth;
|
||||
using Microsoft.AspNetCore.Hosting.Internal;
|
||||
using System.Net;
|
||||
|
||||
namespace SteelToe.Security.Authentication.CloudFoundry.Test
|
||||
{
|
||||
public class CloudFoundryAppBuilderExtensionsTest
|
||||
{
|
||||
[Fact]
|
||||
public void UseCloudFoundryAuthentication_ThowsAppBuilderNull()
|
||||
{
|
||||
// Arrange
|
||||
IApplicationBuilder builder = null;
|
||||
|
||||
// Act and Assert
|
||||
var ex = Assert.Throws<ArgumentNullException>(() => CloudFoundryAppBuilderExtensions.UseCloudFoundryAuthentication(builder));
|
||||
Assert.Contains(nameof(builder), ex.Message);
|
||||
var ex2 = Assert.Throws<ArgumentNullException>(() => CloudFoundryAppBuilderExtensions.UseCloudFoundryAuthentication(builder, new CloudFoundryOptions()));
|
||||
Assert.Contains(nameof(builder), ex2.Message);
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void UseCloudFoundryAuthentication_ThowsCloudFoundryOptionsNull()
|
||||
{
|
||||
// Arrange
|
||||
IApplicationBuilder builder = new ApplicationBuilder(null);
|
||||
CloudFoundryOptions options = null;
|
||||
|
||||
// Act and Assert
|
||||
var ex = Assert.Throws<ArgumentNullException>(() => CloudFoundryAppBuilderExtensions.UseCloudFoundryAuthentication(builder, options));
|
||||
Assert.Contains(nameof(options), ex.Message);
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void UseCloudFoundryAuthentication_AddsMiddlewareIntoPipeline()
|
||||
{
|
||||
IHostingEnvironment envir = new HostingEnvironment();
|
||||
CloudFoundryOptions opts = new CloudFoundryOptions();
|
||||
|
||||
TestServerStartup.CloudFoundryOptions = opts;
|
||||
TestServerStartup.ServiceOptions = null;
|
||||
var builder = new WebHostBuilder().UseStartup<TestServerStartup>().UseEnvironment("development");
|
||||
using (var server = new TestServer(builder))
|
||||
{
|
||||
var client = server.CreateClient();
|
||||
var result = await client.GetAsync("http://localhost/");
|
||||
Assert.Equal(HttpStatusCode.Redirect, result.StatusCode);
|
||||
var location = result.Headers.Location.ToString();
|
||||
Assert.True(location.StartsWith("http://default_oauthserviceurl/oauth/authorize"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void UseCloudFoundryAuthentication_UsesOAuthServiceOptionsIfPresent()
|
||||
{
|
||||
// Arrange
|
||||
OAuthServiceOptions serviceOptions = new OAuthServiceOptions()
|
||||
{
|
||||
ClientId = "ClientId",
|
||||
ClientSecret = "ClientSecret",
|
||||
UserAuthorizationUrl = "http://userauthorizationurl/oauth/authorize",
|
||||
AccessTokenUrl = "http://AccessTokenUrl",
|
||||
UserInfoUrl = "http://UserInfoUrl",
|
||||
TokenInfoUrl = "http://TokenInfoUrl",
|
||||
JwtKeyUrl = "http://JwtKeyUrl",
|
||||
Scope = { "foo", "bar" }
|
||||
};
|
||||
|
||||
IHostingEnvironment envir = new HostingEnvironment();
|
||||
|
||||
TestServerStartup.CloudFoundryOptions = null;
|
||||
TestServerStartup.ServiceOptions = serviceOptions;
|
||||
var builder = new WebHostBuilder().UseStartup<TestServerStartup>().UseEnvironment("development");
|
||||
using (var server = new TestServer(builder))
|
||||
{
|
||||
var client = server.CreateClient();
|
||||
var result = await client.GetAsync("http://localhost/");
|
||||
Assert.Equal(HttpStatusCode.Redirect, result.StatusCode);
|
||||
var location = result.Headers.Location.ToString();
|
||||
Assert.True(location.StartsWith("http://userauthorizationurl/oauth/authorize"));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,339 @@
|
|||
//
|
||||
// Copyright 2015 the original author or authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using Microsoft.AspNetCore.Authentication.OAuth;
|
||||
using Xunit;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using Microsoft.Extensions.Logging.Console;
|
||||
using System.Text.Encodings.Web;
|
||||
using System.Net.Http.Headers;
|
||||
using Microsoft.AspNetCore.Http.Features;
|
||||
using System.IO;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.AspNetCore.Http.Authentication;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using System.Security.Claims;
|
||||
using Microsoft.AspNetCore.Authentication;
|
||||
|
||||
namespace SteelToe.Security.Authentication.CloudFoundry.Test
|
||||
{
|
||||
public class CloudFoundryHandlerTest
|
||||
{
|
||||
|
||||
[Fact]
|
||||
public void GetTokenRequestParameters_ReturnsCorrectly()
|
||||
{
|
||||
HttpClient client = new HttpClient(new TestMessageHandler());
|
||||
MyTestCloudFoundryHandler testHandler = new MyTestCloudFoundryHandler(client);
|
||||
var opts = new CloudFoundryOptions();
|
||||
testHandler.InitializeAsync(opts, new DefaultHttpContext(), new ConsoleLogger("test", null, false), UrlEncoder.Default);
|
||||
|
||||
var parameters = testHandler.GetTokenRequestParameters("code", "redirectUri");
|
||||
Assert.NotNull(parameters);
|
||||
|
||||
|
||||
Assert.Equal(parameters["client_id"], opts.ClientId);
|
||||
Assert.Equal(parameters["redirect_uri"], "redirectUri");
|
||||
Assert.Equal(parameters["client_secret"], opts.ClientSecret);
|
||||
Assert.Equal(parameters["code"], "code");
|
||||
Assert.Equal(parameters["grant_type"], "authorization_code");
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTokenRequestMessage_ReturnsCorrectly()
|
||||
{
|
||||
HttpClient client = new HttpClient(new TestMessageHandler());
|
||||
MyTestCloudFoundryHandler testHandler = new MyTestCloudFoundryHandler(client);
|
||||
var opts = new CloudFoundryOptions();
|
||||
testHandler.InitializeAsync(opts, new DefaultHttpContext(), new ConsoleLogger("test", null, false), UrlEncoder.Default);
|
||||
|
||||
var message = testHandler.GetTokenRequestMessage("code", "redirectUri");
|
||||
Assert.NotNull(message);
|
||||
var content = message.Content as FormUrlEncodedContent;
|
||||
Assert.NotNull(content);
|
||||
Assert.Equal(HttpMethod.Post, message.Method);
|
||||
|
||||
message.Headers.Accept.Contains(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void ExchangeCodeAsync_SendsTokenRequest_ReturnsValidTokenInfo()
|
||||
{
|
||||
TestMessageHandler handler = new TestMessageHandler();
|
||||
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
|
||||
response.Content = new StringContent(TestHelpers.GetValidTokenRequestResponse());
|
||||
handler.Response = response;
|
||||
|
||||
HttpClient client = new HttpClient(handler);
|
||||
MyTestCloudFoundryHandler testHandler = new MyTestCloudFoundryHandler(client);
|
||||
var opts = new CloudFoundryOptions();
|
||||
|
||||
var context = new DefaultHttpContext();
|
||||
context.Features.Set<IHttpResponseFeature>(new TestResponse());
|
||||
|
||||
var logger = new LoggerFactory().CreateLogger("ExchangeCodeAsync_SendsTokenRequest");
|
||||
|
||||
await testHandler.InitializeAsync(opts, context, logger, UrlEncoder.Default);
|
||||
|
||||
var resp = await testHandler.TestExchangeCodeAsync("code", "redirectUri");
|
||||
|
||||
Assert.NotNull(handler.LastRequest);
|
||||
Assert.Equal(HttpMethod.Post, handler.LastRequest.Method);
|
||||
Assert.Equal(opts.TokenEndpoint.ToLowerInvariant(),handler.LastRequest.RequestUri.ToString().ToLowerInvariant());
|
||||
|
||||
|
||||
Assert.NotNull(resp);
|
||||
Assert.NotNull(resp.Response);
|
||||
Assert.Equal("bearer", resp.TokenType);
|
||||
Assert.NotNull(resp.AccessToken);
|
||||
Assert.NotNull(resp.RefreshToken);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void ExchangeCodeAsync_SendsTokenRequest_ReturnsErrorResponse()
|
||||
{
|
||||
TestMessageHandler handler = new TestMessageHandler();
|
||||
var response = new HttpResponseMessage(System.Net.HttpStatusCode.BadRequest);
|
||||
response.Content = new StringContent("");
|
||||
handler.Response = response;
|
||||
|
||||
HttpClient client = new HttpClient(handler);
|
||||
MyTestCloudFoundryHandler testHandler = new MyTestCloudFoundryHandler(client);
|
||||
var opts = new CloudFoundryOptions();
|
||||
|
||||
var context = new DefaultHttpContext();
|
||||
context.Features.Set<IHttpResponseFeature>(new TestResponse());
|
||||
|
||||
var logger = new LoggerFactory().CreateLogger("ExchangeCodeAsync_SendsTokenRequest");
|
||||
|
||||
await testHandler.InitializeAsync(opts, context, logger, UrlEncoder.Default);
|
||||
|
||||
var resp = await testHandler.TestExchangeCodeAsync("code", "redirectUri");
|
||||
|
||||
Assert.NotNull(handler.LastRequest);
|
||||
Assert.Equal(HttpMethod.Post, handler.LastRequest.Method);
|
||||
Assert.Equal(opts.TokenEndpoint.ToLowerInvariant(), handler.LastRequest.RequestUri.ToString().ToLowerInvariant());
|
||||
|
||||
|
||||
Assert.NotNull(resp);
|
||||
Assert.NotNull(resp.Error);
|
||||
Assert.True(resp.Error.Message.Contains("OAuth token endpoint failure"));
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void BuildChallengeUrl_CreatesCorrectUrl()
|
||||
{
|
||||
TestMessageHandler handler = new TestMessageHandler();
|
||||
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
|
||||
response.Content = new StringContent(TestHelpers.GetValidTokenRequestResponse());
|
||||
handler.Response = response;
|
||||
|
||||
HttpClient client = new HttpClient(handler);
|
||||
MyTestCloudFoundryHandler testHandler = new MyTestCloudFoundryHandler(client);
|
||||
var opts = new CloudFoundryOptions();
|
||||
|
||||
var context = new DefaultHttpContext();
|
||||
context.Features.Set<IHttpResponseFeature>(new TestResponse());
|
||||
|
||||
var logger = new LoggerFactory().CreateLogger("ExchangeCodeAsync_SendsTokenRequest");
|
||||
await testHandler.InitializeAsync(opts, context, logger, UrlEncoder.Default);
|
||||
|
||||
AuthenticationProperties props = new AuthenticationProperties();
|
||||
string result = testHandler.TestBuildChallengeUrl(props, "http://foo.bar/redirect");
|
||||
Assert.Equal("http://Default_OAuthServiceUrl/oauth/authorize?response_type=code&client_id=Default_ClientId&redirect_uri=http%3A%2F%2Ffoo.bar%2Fredirect&scope=", result);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTokenInfoRequestParameters_ReturnsCorrectly()
|
||||
{
|
||||
HttpClient client = new HttpClient(new TestMessageHandler());
|
||||
MyTestCloudFoundryHandler testHandler = new MyTestCloudFoundryHandler(client);
|
||||
var opts = new CloudFoundryOptions();
|
||||
testHandler.InitializeAsync(opts, new DefaultHttpContext(), new ConsoleLogger("test", null, false), UrlEncoder.Default);
|
||||
|
||||
var payload = JObject.Parse(TestHelpers.GetValidTokenInfoRequestResponse());
|
||||
var tokens = OAuthTokenResponse.Success(payload);
|
||||
|
||||
var parameters = testHandler.GetTokenInfoRequestParameters(tokens);
|
||||
Assert.NotNull(parameters);
|
||||
|
||||
|
||||
Assert.Equal(parameters["token"], tokens.AccessToken);
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetTokenInfoRequestMessage_ReturnsCorrectly()
|
||||
{
|
||||
HttpClient client = new HttpClient(new TestMessageHandler());
|
||||
MyTestCloudFoundryHandler testHandler = new MyTestCloudFoundryHandler(client);
|
||||
var opts = new CloudFoundryOptions();
|
||||
testHandler.InitializeAsync(opts, new DefaultHttpContext(), new ConsoleLogger("test", null, false), UrlEncoder.Default);
|
||||
|
||||
var payload = JObject.Parse(TestHelpers.GetValidTokenInfoRequestResponse());
|
||||
var tokens = OAuthTokenResponse.Success(payload);
|
||||
|
||||
var message = testHandler.GetTokenInfoRequestMessage(tokens);
|
||||
Assert.NotNull(message);
|
||||
var content = message.Content as FormUrlEncodedContent;
|
||||
Assert.NotNull(content);
|
||||
Assert.Equal(HttpMethod.Post, message.Method);
|
||||
|
||||
message.Headers.Accept.Contains(new MediaTypeWithQualityHeaderValue("application/json"));
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async void CreateTicketAsync_SendsTokenInfoRequest_ReturnsValidTokenInfo()
|
||||
{
|
||||
TestMessageHandler handler = new TestMessageHandler();
|
||||
var response = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
|
||||
response.Content = new StringContent(TestHelpers.GetValidTokenInfoRequestResponse());
|
||||
handler.Response = response;
|
||||
|
||||
HttpClient client = new HttpClient(handler);
|
||||
MyTestCloudFoundryHandler testHandler = new MyTestCloudFoundryHandler(client);
|
||||
var opts = new CloudFoundryOptions();
|
||||
|
||||
var context = new DefaultHttpContext();
|
||||
context.Features.Set<IHttpResponseFeature>(new TestResponse());
|
||||
|
||||
var logger = new LoggerFactory().CreateLogger("CreateTicketAsync_SendsTokenRequest");
|
||||
|
||||
await testHandler.InitializeAsync(opts, context, logger, UrlEncoder.Default);
|
||||
|
||||
ClaimsIdentity identity = new ClaimsIdentity();
|
||||
|
||||
var payload = JObject.Parse(TestHelpers.GetValidTokenInfoRequestResponse());
|
||||
var tokens = OAuthTokenResponse.Success(payload);
|
||||
var resp = await testHandler.TestCreateTicketAsync(identity, new AuthenticationProperties(), tokens);
|
||||
|
||||
Assert.NotNull(handler.LastRequest);
|
||||
Assert.Equal(HttpMethod.Post, handler.LastRequest.Method);
|
||||
Assert.Equal(opts.TokenInfoUrl.ToLowerInvariant(), handler.LastRequest.RequestUri.ToString().ToLowerInvariant());
|
||||
|
||||
Assert.Equal("testssouser", identity.Name);
|
||||
Assert.Equal(4, identity.Claims.Count());
|
||||
identity.HasClaim(ClaimTypes.Email, "testssouser@testcloud.com");
|
||||
identity.HasClaim(ClaimTypes.NameIdentifier, "13bb6841-e4d6-4a9a-876c-9ef13aa61cc7");
|
||||
identity.HasClaim(ClaimTypes.Name, "testssouser");
|
||||
identity.HasClaim("openid", string.Empty);
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
class MyTestCloudFoundryHandler : CloudFoundryHandler
|
||||
{
|
||||
public MyTestCloudFoundryHandler(HttpClient httpClient) : base(httpClient)
|
||||
{
|
||||
|
||||
}
|
||||
public async Task<AuthenticationTicket> TestCreateTicketAsync(ClaimsIdentity identity, AuthenticationProperties properties, OAuthTokenResponse tokens)
|
||||
{
|
||||
return await base.CreateTicketAsync(identity, properties, tokens);
|
||||
}
|
||||
public async Task<OAuthTokenResponse> TestExchangeCodeAsync(string code, string redirectUri)
|
||||
{
|
||||
return await base.ExchangeCodeAsync(code, redirectUri);
|
||||
}
|
||||
|
||||
public string TestBuildChallengeUrl(AuthenticationProperties properties, string redirectUri)
|
||||
{
|
||||
return base.BuildChallengeUrl(properties, redirectUri);
|
||||
}
|
||||
}
|
||||
class TestResponse : IHttpResponseFeature
|
||||
{
|
||||
public Stream Body
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public bool HasStarted
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public IHeaderDictionary Headers
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public string ReasonPhrase
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public int StatusCode
|
||||
{
|
||||
get
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
|
||||
public void OnCompleted(Func<object, Task> callback, object state)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void OnStarting(Func<object, Task> callback, object state)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,118 @@
|
|||
//
|
||||
// Copyright 2015 the original author or authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
using Microsoft.AspNetCore.Http;
|
||||
using SteelToe.CloudFoundry.Connector.OAuth;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
using Xunit;
|
||||
|
||||
namespace SteelToe.Security.Authentication.CloudFoundry.Test
|
||||
{
|
||||
public class CloudFoundryOptionsTest
|
||||
{
|
||||
[Fact]
|
||||
public void DefaultConstructor_SetsupDefaultOptions()
|
||||
{
|
||||
CloudFoundryOptions opts = new CloudFoundryOptions();
|
||||
|
||||
string authURL = "http://" + CloudFoundryOptions.Default_OAuthServiceUrl;
|
||||
Assert.Equal(CloudFoundryOptions.AUTHENTICATION_SCHEME, opts.ClaimsIssuer);
|
||||
Assert.Equal(CloudFoundryOptions.Default_ClientId, opts.ClientId );
|
||||
Assert.Equal(CloudFoundryOptions.Default_ClientSecret, opts.ClientSecret );
|
||||
Assert.Equal(CloudFoundryOptions.AUTHENTICATION_SCHEME, opts.AuthenticationScheme );
|
||||
Assert.Equal(CloudFoundryOptions.AUTHENTICATION_SCHEME, opts.DisplayName );
|
||||
Assert.Equal(new PathString("/signin-cloudfoundry"), opts.CallbackPath );
|
||||
Assert.Equal(authURL + CloudFoundryOptions.Default_AuthorizationUri, opts.AuthorizationEndpoint );
|
||||
Assert.Equal(authURL + CloudFoundryOptions.Default_AccessTokenUri, opts.TokenEndpoint ) ;
|
||||
Assert.Equal(authURL + CloudFoundryOptions.Default_UserInfoUri, opts.UserInformationEndpoint );
|
||||
Assert.Equal(authURL + CloudFoundryOptions.Default_CheckTokenUri, opts.TokenInfoUrl) ;
|
||||
Assert.Equal(authURL + CloudFoundryOptions.Default_JwtTokenKey, opts.JwtKeyUrl );
|
||||
Assert.True(opts.ValidateCertificates);
|
||||
|
||||
}
|
||||
[Fact]
|
||||
public void OAuthServiceOptionsConstructor_SetsupOptionsAsExpected()
|
||||
{
|
||||
OAuthServiceOptions oauthOpts = new OAuthServiceOptions()
|
||||
{
|
||||
ClientId = "ClientId",
|
||||
ClientSecret = "ClientSecret",
|
||||
UserAuthorizationUrl = "UserAuthorizationUrl",
|
||||
AccessTokenUrl = "AccessTokenUrl",
|
||||
UserInfoUrl = "UserInfoUrl",
|
||||
TokenInfoUrl = "TokenInfoUrl",
|
||||
JwtKeyUrl = "JwtKeyUrl",
|
||||
Scope = { "foo", "bar" }
|
||||
};
|
||||
|
||||
CloudFoundryOptions opts = new CloudFoundryOptions(oauthOpts);
|
||||
|
||||
Assert.Equal(CloudFoundryOptions.AUTHENTICATION_SCHEME, opts.ClaimsIssuer);
|
||||
Assert.Equal("ClientId", opts.ClientId);
|
||||
Assert.Equal("ClientSecret", opts.ClientSecret);
|
||||
Assert.Equal(CloudFoundryOptions.AUTHENTICATION_SCHEME, opts.AuthenticationScheme);
|
||||
Assert.Equal(CloudFoundryOptions.AUTHENTICATION_SCHEME, opts.DisplayName);
|
||||
Assert.Equal(new PathString("/signin-cloudfoundry"), opts.CallbackPath);
|
||||
Assert.Equal("UserAuthorizationUrl", opts.AuthorizationEndpoint);
|
||||
Assert.Equal("AccessTokenUrl", opts.TokenEndpoint);
|
||||
Assert.Equal("UserInfoUrl", opts.UserInformationEndpoint);
|
||||
Assert.Equal("TokenInfoUrl", opts.TokenInfoUrl);
|
||||
Assert.Equal("JwtKeyUrl", opts.JwtKeyUrl);
|
||||
Assert.True(opts.Scope.Contains("foo"));
|
||||
Assert.True(opts.Scope.Contains("bar"));
|
||||
Assert.True(opts.ValidateCertificates);
|
||||
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void GetBackChannelHandler_ReturnsCorrectly()
|
||||
{
|
||||
if (RuntimeInformation.IsOSPlatform(OSPlatform.Windows)) {
|
||||
|
||||
CloudFoundryOptions opts = new CloudFoundryOptions();
|
||||
Assert.Null(opts.GetBackChannelHandler());
|
||||
|
||||
opts = new CloudFoundryOptions()
|
||||
{
|
||||
ValidateCertificates = false
|
||||
};
|
||||
Assert.NotNull(opts.GetBackChannelHandler());
|
||||
|
||||
OAuthServiceOptions oauthOpts = new OAuthServiceOptions()
|
||||
{
|
||||
ClientId = "ClientId",
|
||||
ClientSecret = "ClientSecret",
|
||||
UserAuthorizationUrl = "UserAuthorizationUrl",
|
||||
AccessTokenUrl = "AccessTokenUrl",
|
||||
UserInfoUrl = "UserInfoUrl",
|
||||
TokenInfoUrl = "TokenInfoUrl",
|
||||
JwtKeyUrl = "JwtKeyUrl",
|
||||
Scope = { "foo", "bar" }
|
||||
};
|
||||
|
||||
opts = new CloudFoundryOptions(oauthOpts);
|
||||
Assert.Null(opts.GetBackChannelHandler());
|
||||
|
||||
opts = new CloudFoundryOptions(oauthOpts)
|
||||
{
|
||||
ValidateCertificates = false
|
||||
};
|
||||
Assert.NotNull(opts.GetBackChannelHandler());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,19 @@
|
|||
using System.Reflection;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Runtime.InteropServices;
|
||||
|
||||
// General Information about an assembly is controlled through the following
|
||||
// set of attributes. Change these attribute values to modify the information
|
||||
// associated with an assembly.
|
||||
[assembly: AssemblyConfiguration("")]
|
||||
[assembly: AssemblyCompany("")]
|
||||
[assembly: AssemblyProduct("SteelToe.Security.Authentication.CloudFoundry.Test")]
|
||||
[assembly: AssemblyTrademark("")]
|
||||
|
||||
// Setting ComVisible to false makes the types in this assembly not visible
|
||||
// to COM components. If you need to access a type in this assembly from
|
||||
// COM, set the ComVisible attribute to true on that type.
|
||||
[assembly: ComVisible(false)]
|
||||
|
||||
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||
[assembly: Guid("0b258f76-09d9-44fe-8232-cbf33f68242c")]
|
|
@ -0,0 +1,22 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">14.0</VisualStudioVersion>
|
||||
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
|
||||
</PropertyGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.Props" Condition="'$(VSToolsPath)' != ''" />
|
||||
<PropertyGroup Label="Globals">
|
||||
<ProjectGuid>0b258f76-09d9-44fe-8232-cbf33f68242c</ProjectGuid>
|
||||
<RootNamespace>SteelToe.Security.Authentication.CloudFoundry.Test</RootNamespace>
|
||||
<BaseIntermediateOutputPath Condition="'$(BaseIntermediateOutputPath)'=='' ">.\obj</BaseIntermediateOutputPath>
|
||||
<OutputPath Condition="'$(OutputPath)'=='' ">.\bin\</OutputPath>
|
||||
<TargetFrameworkVersion>v4.5.2</TargetFrameworkVersion>
|
||||
</PropertyGroup>
|
||||
<PropertyGroup>
|
||||
<SchemaVersion>2.0</SchemaVersion>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Service Include="{82a7f48d-3b50-4b1e-b82e-3ada8210c358}" />
|
||||
</ItemGroup>
|
||||
<Import Project="$(VSToolsPath)\DotNet\Microsoft.DotNet.targets" Condition="'$(VSToolsPath)' != ''" />
|
||||
</Project>
|
|
@ -0,0 +1,74 @@
|
|||
//
|
||||
// Copyright 2015 the original author or authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
using System.IO;
|
||||
using System.Net.Http;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace SteelToe.Security.Authentication.CloudFoundry.Test
|
||||
{
|
||||
public class TestHelpers
|
||||
{
|
||||
public static string CreateTempFile(string contents)
|
||||
{
|
||||
var tempFile = Path.GetTempFileName();
|
||||
File.WriteAllText(tempFile, contents);
|
||||
return tempFile;
|
||||
|
||||
}
|
||||
public static Stream StringToStream(string str)
|
||||
{
|
||||
var memStream = new MemoryStream();
|
||||
var textWriter = new StreamWriter(memStream);
|
||||
textWriter.Write(str);
|
||||
textWriter.Flush();
|
||||
memStream.Seek(0, SeekOrigin.Begin);
|
||||
|
||||
return memStream;
|
||||
}
|
||||
|
||||
public static string StreamToString(Stream stream)
|
||||
{
|
||||
stream.Seek(0, SeekOrigin.Begin);
|
||||
var reader = new StreamReader(stream);
|
||||
|
||||
return reader.ReadToEnd();
|
||||
}
|
||||
|
||||
public static string GetValidTokenRequestResponse()
|
||||
{
|
||||
return @"{'access_token':'eyJhbGciOiJSUzI1NiIsImtpZCI6ImxlZ2FjeS10b2tlbi1rZXkiLCJ0eXAiOiJKV1QifQ.eyJqdGkiOiJjNjUxZGI2NjllODM0NGNkOTMwMGUxYjJkYjUxOTgwZCIsInN1YiI6IjEzYmI2ODQxLWU0ZDYtNGE5YS04NzZjLTllZjEzYWE2MWNjNyIsInNjb3BlIjpbIm9wZW5pZCJdLCJjbGllbnRfaWQiOiI0NGY4NTRmZC00OWZlLTQxMDItYjBkMS1hNTI2ZGJmZjkzZDkiLCJjaWQiOiI0NGY4NTRmZC00OWZlLTQxMDItYjBkMS1hNTI2ZGJmZjkzZDkiLCJhenAiOiI0NGY4NTRmZC00OWZlLTQxMDItYjBkMS1hNTI2ZGJmZjkzZDkiLCJncmFudF90eXBlIjoiYXV0aG9yaXphdGlvbl9jb2RlIiwidXNlcl9pZCI6IjEzYmI2ODQxLWU0ZDYtNGE5YS04NzZjLTllZjEzYWE2MWNjNyIsIm9yaWdpbiI6InVhYSIsInVzZXJfbmFtZSI6InRlc3Rzc291c2VyIiwiZW1haWwiOiJ0ZXN0c3NvdXNlckB0ZXN0Y2xvdWQuY29tIiwiYXV0aF90aW1lIjoxNDcyNzUxNDUyLCJyZXZfc2lnIjoiNTExMzU4NDIiLCJpYXQiOjE0NzI3NTE0NTIsImV4cCI6MTQ3Mjc5NDY1MiwiaXNzIjoiaHR0cHM6Ly90ZXN0c3NvLnVhYS5zeXN0ZW0udGVzdGNsb3VkLmNvbS9vYXV0aC90b2tlbiIsInppZCI6ImVmMzA0ZWQwLTNhNWEtNDQyZS05YWQ4LWU0Y2EzYWQ1MTIwZSIsImF1ZCI6WyI0NGY4NTRmZC00OWZlLTQxMDItYjBkMS1hNTI2ZGJmZjkzZDkiLCJvcGVuaWQiXX0.f6CA7WrGrY__CNh - RvY1pl05 - 2PQjeyE7C_OH48ChfoxsL4hO8BJEofz934_Jox6dXJwp3wyeMPYwyS5fKGA3ASJT5KqdZ8QdHhOj7lbcejwTUUfG_t - K26W39BLT - cEbpTFyHzBUK79fhIfwSmmXJWU0vQaZ3F0dYKRm98rCEQo9s5jr2jrqHep52vL3Xo8mwDJO4GBc85p8zzVpUPOYMkKiWfEujIOvBL0yTqAL64NsYmFupbKyt5dgf - eF - 1GOuP7Rbgbk_llQuFOkwYr4dLzgw045wXeU3uzJzTrGNzIlJQPOijU1w2uBgYi7fT2wgJDKb4toxot2_6wSXpqBw','token_type':'bearer','refresh_token':'eyJhbGciOiJSUzI1NiIsImtpZCI6ImxlZ2FjeS10b2tlbi1rZXkiLCJ0eXAiOiJKV1QifQ.eyJqdGkiOiJjNjUxZGI2NjllODM0NGNkOTMwMGUxYjJkYjUxOTgwZC1yIiwic3ViIjoiMTNiYjY4NDEtZTRkNi00YTlhLTg3NmMtOWVmMTNhYTYxY2M3Iiwic2NvcGUiOlsib3BlbmlkIl0sImlhdCI6MTQ3Mjc1MTQ1MiwiZXhwIjoxNDc1MzQzNDUyLCJjaWQiOiI0NGY4NTRmZC00OWZlLTQxMDItYjBkMS1hNTI2ZGJmZjkzZDkiLCJjbGllbnRfaWQiOiI0NGY4NTRmZC00OWZlLTQxMDItYjBkMS1hNTI2ZGJmZjkzZDkiLCJpc3MiOiJodHRwczovL3Rlc3Rzc28udWFhLnN5c3RlbS50ZXN0Y2xvdWQuY29tL29hdXRoL3Rva2VuIiwiemlkIjoiZWYzMDRlZDAtM2E1YS00NDJlLTlhZDgtZTRjYTNhZDUxMjBlIiwiZ3JhbnRfdHlwZSI6ImF1dGhvcml6YXRpb25fY29kZSIsInVzZXJfbmFtZSI6InRlc3Rzc291c2VyIiwib3JpZ2luIjoidWFhIiwidXNlcl9pZCI6IjEzYmI2ODQxLWU0ZDYtNGE5YS04NzZjLTllZjEzYWE2MWNjNyIsInJldl9zaWciOiI1MTEzNTg0MiIsImF1ZCI6WyI0NGY4NTRmZC00OWZlLTQxMDItYjBkMS1hNTI2ZGJmZjkzZDkiLCJvcGVuaWQiXX0.WMEZtwvoJXU8njysozaNglmpYouxoY65AirXC3ypdLsnSVE_OtePQQi3hb3YPQDbrc6JAETnCGcDBJVNUPsnlg4g_O_RPLejB4ZlMioRTZRNv9gzOlELqjgBLAVEkWOiBFuH7hwbR7X7DlmFTcDFSc - gQY5TaLn - wR6PVtQM3oRw_nx1f3 - xgDGcYx7Ktk9rov - xF_C0Pzsoet4dvG78YUlnXgR08KwJnDX_ElV - 0vTOtybqjs_XGSS9N39EWeeykCzciddhqVCfmMM5VMCVaP - 7pr - VDz0N8ArSWfOobI4nPqcj50wvPb595SgId - NlNP4fBX1ibnCeOxWwuzId0w','expires_in':43199,'scope':'openid','jti':'c651db669e8344cd9300e1b2db51980d'}";
|
||||
}
|
||||
|
||||
public static string GetValidTokenInfoRequestResponse()
|
||||
{
|
||||
return @"{'user_id':'13bb6841-e4d6-4a9a-876c-9ef13aa61cc7','user_name':'testssouser','email':'testssouser@testcloud.com','client_id':'44f854fd-49fe-4102-b0d1-a526dbff93d9','exp':1472803463,'scope':['openid'],'jti':'cc956120c52a431fbbb8945ac42872fd','aud':['44f854fd-49fe-4102-b0d1-a526dbff93d9','openid'],'sub':'13bb6841-e4d6-4a9a-876c-9ef13aa61cc7','iss':'https://testsso.uaa.system.testcloud.com/oauth/token','iat':1472760263,'cid':'44f854fd-49fe-4102-b0d1-a526dbff93d9','grant_type':'authorization_code','azp':'44f854fd-49fe-4102-b0d1-a526dbff93d9','auth_time':1472760254,'zid':'ef304ed0-3a5a-442e-9ad8-e4ca3ad5120e','rev_sig':'51135842','origin':'uaa','revocable':false}";
|
||||
}
|
||||
}
|
||||
|
||||
class TestMessageHandler : HttpMessageHandler
|
||||
{
|
||||
public HttpRequestMessage LastRequest { get; set; }
|
||||
public HttpResponseMessage Response { get; set; } = new HttpResponseMessage(System.Net.HttpStatusCode.OK);
|
||||
protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
|
||||
{
|
||||
LastRequest = request;
|
||||
return Task.FromResult<HttpResponseMessage>(Response);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,98 @@
|
|||
//
|
||||
// Copyright 2015 the original author or authors.
|
||||
//
|
||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||
// you may not use this file except in compliance with the License.
|
||||
// You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
//
|
||||
|
||||
using Microsoft.AspNetCore.Authentication.Cookies;
|
||||
using Microsoft.AspNetCore.Builder;
|
||||
using Microsoft.AspNetCore.Http;
|
||||
|
||||
using Microsoft.Extensions.DependencyInjection;
|
||||
using Microsoft.Extensions.Logging;
|
||||
using Microsoft.Extensions.Options;
|
||||
using SteelToe.CloudFoundry.Connector.OAuth;
|
||||
using System;
|
||||
|
||||
|
||||
namespace SteelToe.Security.Authentication.CloudFoundry.Test
|
||||
{
|
||||
public class TestServerStartup
|
||||
{
|
||||
|
||||
public static CloudFoundryOptions CloudFoundryOptions { get; set; }
|
||||
|
||||
public static OAuthServiceOptions ServiceOptions { get; set; }
|
||||
|
||||
public TestServerStartup()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public void ConfigureServices(IServiceCollection services)
|
||||
{
|
||||
services.AddOptions();
|
||||
services.AddAuthentication(options =>
|
||||
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme);
|
||||
|
||||
if (ServiceOptions != null)
|
||||
{
|
||||
services.AddSingleton(typeof(IOptions<OAuthServiceOptions>), Options.Create(ServiceOptions));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public void Configure(IApplicationBuilder app, ILoggerFactory loggerfactory)
|
||||
{
|
||||
loggerfactory.AddConsole(LogLevel.Debug);
|
||||
|
||||
app.Use(async (context, next) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
await next();
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
if (context.Response.HasStarted)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
context.Response.StatusCode = 500;
|
||||
await context.Response.WriteAsync(ex.ToString());
|
||||
}
|
||||
});
|
||||
|
||||
app.UseCookieAuthentication(new CookieAuthenticationOptions
|
||||
{
|
||||
AutomaticAuthenticate = true
|
||||
|
||||
});
|
||||
if (CloudFoundryOptions != null)
|
||||
app.UseCloudFoundryAuthentication(CloudFoundryOptions);
|
||||
else
|
||||
app.UseCloudFoundryAuthentication();
|
||||
|
||||
|
||||
app.Run(async context =>
|
||||
{
|
||||
await context.Authentication.ChallengeAsync(CloudFoundryOptions.AUTHENTICATION_SCHEME);
|
||||
return;
|
||||
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
{
|
||||
"version": "1.0.0",
|
||||
"testRunner": "xunit",
|
||||
"description": "Unit test project for SteelToe.CloudFoundry.Connector.SingleSignon",
|
||||
"authors": [ "Pivotal", "dtillman" ],
|
||||
"packOptions": {
|
||||
"tags": [ "ASPNET Core", "Provider", "CloudFoundry", "OAuth", "Security", "Single Sign-On" ],
|
||||
"projectUrl": "http://steeltoe.io",
|
||||
"licenseUrl": "http://www.apache.org/licenses/LICENSE-2.0",
|
||||
"copyright": "Copyright 2016 the original authors"
|
||||
},
|
||||
"frameworks": {
|
||||
"netcoreapp1.0": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.App": {
|
||||
"type": "platform",
|
||||
"version": "1.0.0"
|
||||
},
|
||||
"System.Threading.Thread": "4.0.0"
|
||||
},
|
||||
"imports": [
|
||||
"dnxcore50",
|
||||
"portable-net451+win8"
|
||||
]
|
||||
},
|
||||
"net451": {
|
||||
"dependencies": {
|
||||
"Microsoft.NETCore.Platforms": "1.0.1-*"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"Microsoft.Extensions.Configuration": "1.0.0",
|
||||
"Microsoft.Extensions.Configuration.Abstractions": "1.0.0",
|
||||
"Microsoft.Extensions.Configuration.FileExtensions": "1.0.0",
|
||||
"Microsoft.Extensions.Configuration.Json": "1.0.0",
|
||||
"SteelToe.Security.Authentication.CloudFoundry": "1.0.0-*",
|
||||
"xunit": "2.2.0-beta2-build3300",
|
||||
"dotnet-test-xunit": "2.2.0-preview2-build1029",
|
||||
"Microsoft.AspNetCore.Hosting": "1.0.0",
|
||||
"Microsoft.AspNetCore.TestHost": "1.0.0",
|
||||
"Microsoft.AspNetCore.Mvc": "1.0.0",
|
||||
"Microsoft.AspNetCore.Http.Abstractions": "1.0.0",
|
||||
"Microsoft.Extensions.Logging.Console": "1.0.0",
|
||||
"Microsoft.AspNetCore.Identity": "1.0.0",
|
||||
"Microsoft.AspNetCore.Identity.EntityFrameworkCore": "1.0.0"
|
||||
},
|
||||
"buildOptions": {
|
||||
"copyToOutput": {
|
||||
"include": [ "xunit.runner.json" ]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,4 @@
|
|||
{
|
||||
"maxParallelThreads": 1,
|
||||
"parallelizeTestCollections": false
|
||||
}
|
Загрузка…
Ссылка в новой задаче