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/
|
[Rr]eleases/
|
||||||
x64/
|
x64/
|
||||||
x86/
|
x86/
|
||||||
|
build/
|
||||||
bld/
|
bld/
|
||||||
[Bb]in/
|
[Bb]in/
|
||||||
[Oo]bj/
|
[Oo]bj/
|
||||||
[Ll]og/
|
|
||||||
|
|
||||||
# Visual Studio 2015 cache/options directory
|
# Visual Studo 2015 cache/options directory
|
||||||
.vs/
|
.vs/
|
||||||
# Uncomment if you have tasks that create the project's static files in wwwroot
|
|
||||||
#wwwroot/
|
|
||||||
|
|
||||||
# MSTest test Results
|
# MSTest test Results
|
||||||
[Tt]est[Rr]esult*/
|
[Tt]est[Rr]esult*/
|
||||||
|
@ -40,10 +38,6 @@ TestResult.xml
|
||||||
[Rr]eleasePS/
|
[Rr]eleasePS/
|
||||||
dlldata.c
|
dlldata.c
|
||||||
|
|
||||||
# DNX
|
|
||||||
project.lock.json
|
|
||||||
artifacts/
|
|
||||||
|
|
||||||
*_i.c
|
*_i.c
|
||||||
*_p.c
|
*_p.c
|
||||||
*_i.h
|
*_i.h
|
||||||
|
@ -76,18 +70,14 @@ _Chutzpah*
|
||||||
ipch/
|
ipch/
|
||||||
*.aps
|
*.aps
|
||||||
*.ncb
|
*.ncb
|
||||||
*.opendb
|
|
||||||
*.opensdf
|
*.opensdf
|
||||||
*.sdf
|
*.sdf
|
||||||
*.cachefile
|
*.cachefile
|
||||||
*.VC.db
|
|
||||||
*.VC.VC.opendb
|
|
||||||
|
|
||||||
# Visual Studio profiler
|
# Visual Studio profiler
|
||||||
*.psess
|
*.psess
|
||||||
*.vsp
|
*.vsp
|
||||||
*.vspx
|
*.vspx
|
||||||
*.sap
|
|
||||||
|
|
||||||
# TFS 2012 Local Workspace
|
# TFS 2012 Local Workspace
|
||||||
$tf/
|
$tf/
|
||||||
|
@ -100,7 +90,7 @@ _ReSharper*/
|
||||||
*.[Rr]e[Ss]harper
|
*.[Rr]e[Ss]harper
|
||||||
*.DotSettings.user
|
*.DotSettings.user
|
||||||
|
|
||||||
# JustCode is a .NET coding add-in
|
# JustCode is a .NET coding addin-in
|
||||||
.JustCode
|
.JustCode
|
||||||
|
|
||||||
# TeamCity is a build add-in
|
# TeamCity is a build add-in
|
||||||
|
@ -112,7 +102,6 @@ _TeamCity*
|
||||||
# NCrunch
|
# NCrunch
|
||||||
_NCrunch_*
|
_NCrunch_*
|
||||||
.*crunch*.local.xml
|
.*crunch*.local.xml
|
||||||
nCrunchTemp_*
|
|
||||||
|
|
||||||
# MightyMoose
|
# MightyMoose
|
||||||
*.mm.*
|
*.mm.*
|
||||||
|
@ -140,16 +129,11 @@ publish/
|
||||||
# Publish Web Output
|
# Publish Web Output
|
||||||
*.[Pp]ublish.xml
|
*.[Pp]ublish.xml
|
||||||
*.azurePubxml
|
*.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
|
# but database connection strings (with potential passwords) will be unencrypted
|
||||||
*.pubxml
|
*.pubxml
|
||||||
*.publishproj
|
*.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
|
# NuGet Packages
|
||||||
*.nupkg
|
*.nupkg
|
||||||
# The packages folder can be ignored because of Package Restore
|
# The packages folder can be ignored because of Package Restore
|
||||||
|
@ -158,32 +142,18 @@ PublishScripts/
|
||||||
!**/packages/build/
|
!**/packages/build/
|
||||||
# Uncomment if necessary however generally it will be regenerated when needed
|
# Uncomment if necessary however generally it will be regenerated when needed
|
||||||
#!**/packages/repositories.config
|
#!**/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/
|
csx/
|
||||||
*.build.csdef
|
*.build.csdef
|
||||||
|
|
||||||
# Microsoft Azure Emulator
|
# Windows Store app package directory
|
||||||
ecf/
|
|
||||||
rcf/
|
|
||||||
|
|
||||||
# Windows Store app package directories and files
|
|
||||||
AppPackages/
|
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
|
# Others
|
||||||
|
*.[Cc]ache
|
||||||
ClientBin/
|
ClientBin/
|
||||||
|
[Ss]tyle[Cc]op.*
|
||||||
~$*
|
~$*
|
||||||
*~
|
*~
|
||||||
*.dbmdl
|
*.dbmdl
|
||||||
|
@ -191,11 +161,7 @@ ClientBin/
|
||||||
*.pfx
|
*.pfx
|
||||||
*.publishsettings
|
*.publishsettings
|
||||||
node_modules/
|
node_modules/
|
||||||
orleans.codegen.cs
|
bower_components/
|
||||||
|
|
||||||
# Since there are multiple workflows, uncomment next line to ignore bower_components
|
|
||||||
# (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
|
|
||||||
#bower_components/
|
|
||||||
|
|
||||||
# RIA/Silverlight projects
|
# RIA/Silverlight projects
|
||||||
Generated_Code/
|
Generated_Code/
|
||||||
|
@ -220,9 +186,6 @@ UpgradeLog*.htm
|
||||||
# Microsoft Fakes
|
# Microsoft Fakes
|
||||||
FakesAssemblies/
|
FakesAssemblies/
|
||||||
|
|
||||||
# GhostDoc plugin setting file
|
|
||||||
*.GhostDoc.xml
|
|
||||||
|
|
||||||
# Node.js Tools for Visual Studio
|
# Node.js Tools for Visual Studio
|
||||||
.ntvs_analysis.dat
|
.ntvs_analysis.dat
|
||||||
|
|
||||||
|
@ -232,21 +195,6 @@ FakesAssemblies/
|
||||||
# Visual Studio 6 workspace options file
|
# Visual Studio 6 workspace options file
|
||||||
*.opt
|
*.opt
|
||||||
|
|
||||||
# Visual Studio LightSwitch build output
|
# DNX-based projects have a project.lock.json file. This should not be checked-in during development
|
||||||
**/*.HTMLClient/GeneratedArtifacts
|
project.lock.json
|
||||||
**/*.DesktopClient/GeneratedArtifacts
|
|
||||||
**/*.DesktopClient/ModelManifest.xml
|
|
||||||
**/*.Server/GeneratedArtifacts
|
|
||||||
**/*.Server/ModelManifest.xml
|
|
||||||
_Pvt_Extensions
|
|
||||||
|
|
||||||
# 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
|
||||||
|
}
|
Загрузка…
Ссылка в новой задаче