├── .github
└── ISSUE_TEMPLATE
│ ├── bug_report.md
│ └── feature_request.md
├── .gitignore
├── .vscode
├── launch.json
└── tasks.json
├── ApigeeToApimMigrationTool.DataAccess
├── ApigeeToApimMigrationTool.DataAccess.csproj
└── ProxyMetaDataDataAccess.cs
├── ApigeeToApimMigrationTool.Database
├── ApigeeToApimMigrationTool.Database.sqlproj
├── StoredProcedures
│ └── DeleteAllData.sql
└── Tables
│ ├── Proxy.sql
│ ├── ProxyBasePath.sql
│ ├── ProxyEndpoint.sql
│ └── ProxyPolicy.sql
├── ApigeeToApimMigrationTool.Test
├── ApigeeToApimMigrationTool.Test.csproj
├── AzureApimServiceTest.cs
├── AzureSdkMocks
│ ├── MockApiManagementProductResource.cs
│ └── MockApiResource.cs
├── BundleLoaderTests.cs
├── MockApigeeManagementApiService.cs
├── MockApigeeXmlLoader.cs
├── MockApimProvider.cs
├── MockBundleProvider.cs
├── MockPolicyTransformer.cs
├── TestBundles
│ ├── GetSharedFlow
│ │ └── sharedflowbundle
│ │ │ ├── GetSharedFlow.xml
│ │ │ ├── policies
│ │ │ └── Get-Shared-Flow.xml
│ │ │ └── sharedflows
│ │ │ └── default.xml
│ └── Test-API
│ │ └── apiproxy
│ │ ├── Test-API.xml
│ │ ├── policies
│ │ └── SharedFlowCallout.xml
│ │ ├── proxies
│ │ └── default.xml
│ │ └── targets
│ │ └── default.xml
├── TransformationTests
│ └── AssignMessageTransformationTests.cs
└── Usings.cs
├── ApigeeToApimMigrationTool.sln
├── ApigeeToApimMigrationTool
├── ApigeeToApimMigrationTool.csproj
├── Program.cs
├── Properties
│ └── launchSettings.json
└── apigeeToApimConfig.SAMPLE.json
├── ApigeeToAzureApimMigrationTool.Core
├── ApigeeToAzureApimMigrationTool.Core.csproj
├── Config
│ ├── ApigeeConfiguration.cs
│ ├── ApigeeConfigurationBinder.cs
│ ├── ApimConfiguration.cs
│ ├── ApimConfigurationBinder.cs
│ ├── EntraConfiguration.cs
│ └── EntraConfigurationBinder.cs
├── Dto
│ ├── ApiProductMetaData.cs
│ ├── ApiProxyEndpointMetadata.cs
│ ├── ApiProxyMetaData.cs
│ ├── ApiProxyRevisionMetadata.cs
│ ├── ApigeeEntityModel.cs
│ ├── ApigeeTargetServerModel.cs
│ ├── ApimConfig.cs
│ ├── AuthToken.cs
│ ├── AzureCredentials.cs
│ └── KeyValueMapModel.cs
├── Enum
│ ├── AssignMessagePolicyOperations.cs
│ └── PolicyDirection.cs
└── Interface
│ ├── IApigeeManagementApiService.cs
│ ├── IApigeeXmlLoader.cs
│ ├── IApimPolicyTransformer.cs
│ ├── IApimProvider.cs
│ ├── IAzureApimService.cs
│ ├── IBundle.cs
│ ├── IBundleProvider.cs
│ ├── IExpressionTranslator.cs
│ ├── IPolicyTransformation.cs
│ ├── IPolicyTransformationFactory.cs
│ └── IProxyMetaDataDataAccess.cs
├── ApigeeToAzureApimMigrationTool.Logic
├── ApigeeManagementApiService.cs
├── ApigeeManagementApiTestFileService.cs
├── ApigeeToApimPolicyTransformer.cs
├── ApigeeToAzureApimMigrationTool.Service.csproj
├── ApigeeXmlFileLoader.cs
├── AzureApimProvider.cs
├── AzureApimService.cs
├── Bundles
│ ├── ApigeeFileApiProxyBundle.cs
│ ├── ApigeeFileBundleProvider.cs
│ ├── ApigeeFileSharedFlowBundle.cs
│ ├── ApigeeOnlineApiProxyBundle.cs
│ ├── ApigeeOnlineBundleProvider.cs
│ └── ApigeeOnlineSharedFlowBundle.cs
├── ExpressionTranslator.cs
└── Transformations
│ ├── AccessControlTransformation.cs
│ ├── AssignMessageTransformation.cs
│ ├── BasicAuthenticationTransformation.cs
│ ├── ExtractVariablesTransformation.cs
│ ├── FlowCalloutTransformation.cs
│ ├── InvalidateCacheTransformation.cs
│ ├── KeyValueMapTransformation.cs
│ ├── LookupCacheTransformation.cs
│ ├── NullTransformation.cs
│ ├── OAuthV2Transformation.cs
│ ├── PolicyTransformationFactory.cs
│ ├── PopulateCacheTransformation.cs
│ ├── RaiseFaultTransformation.cs
│ ├── ServiceCalloutTransformation.cs
│ ├── SpikeArrestTransformation.cs
│ └── VerifyJwtTransformation.cs
├── CODEOWNERS
├── CODE_OF_CONDUCT.md
├── LICENSE
├── README.md
├── Roadmap.md
├── SECURITY.md
└── SUPPORT.md
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Describe the bug**
11 | A clear and concise description of what the bug is.
12 |
13 | **To Reproduce**
14 | Steps to reproduce the behavior:
15 | 1. Go to '...'
16 | 2. Click on '....'
17 | 3. Scroll down to '....'
18 | 4. See error
19 |
20 | **Expected behavior**
21 | A clear and concise description of what you expected to happen.
22 |
23 | **Screenshots**
24 | If applicable, add screenshots to help explain your problem.
25 |
26 | **Desktop (please complete the following information):**
27 | - OS: [e.g. iOS]
28 | - Browser [e.g. chrome, safari]
29 | - Version [e.g. 22]
30 |
31 | **Smartphone (please complete the following information):**
32 | - Device: [e.g. iPhone6]
33 | - OS: [e.g. iOS8.1]
34 | - Browser [e.g. stock browser, safari]
35 | - Version [e.g. 22]
36 |
37 | **Additional context**
38 | Add any other context about the problem here.
39 |
--------------------------------------------------------------------------------
/.github/ISSUE_TEMPLATE/feature_request.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Feature request
3 | about: Suggest an idea for this project
4 | title: ''
5 | labels: ''
6 | assignees: ''
7 |
8 | ---
9 |
10 | **Is your feature request related to a problem? Please describe.**
11 | A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
12 |
13 | **Describe the solution you'd like**
14 | A clear and concise description of what you want to happen.
15 |
16 | **Describe alternatives you've considered**
17 | A clear and concise description of any alternative solutions or features you've considered.
18 |
19 | **Additional context**
20 | Add any other context or screenshots about the feature request here.
21 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | ## Ignore Visual Studio temporary files, build results, and
2 | ## files generated by popular Visual Studio add-ons.
3 | ##
4 | ## Get latest from https://github.com/github/gitignore/blob/main/VisualStudio.gitignore
5 |
6 | # User-specific files
7 | *.rsuser
8 | *.suo
9 | *.user
10 | *.userosscache
11 | *.sln.docstates
12 |
13 | # User-specific files (MonoDevelop/Xamarin Studio)
14 | *.userprefs
15 |
16 | # Mono auto generated files
17 | mono_crash.*
18 |
19 | # Build results
20 | [Dd]ebug/
21 | [Dd]ebugPublic/
22 | [Rr]elease/
23 | [Rr]eleases/
24 | x64/
25 | x86/
26 | [Ww][Ii][Nn]32/
27 | [Aa][Rr][Mm]/
28 | [Aa][Rr][Mm]64/
29 | bld/
30 | [Bb]in/
31 | [Oo]bj/
32 | [Ll]og/
33 | [Ll]ogs/
34 |
35 | # Visual Studio 2015/2017 cache/options directory
36 | .vs/
37 | # Uncomment if you have tasks that create the project's static files in wwwroot
38 | #wwwroot/
39 |
40 | # Visual Studio 2017 auto generated files
41 | Generated\ Files/
42 |
43 | # MSTest test Results
44 | [Tt]est[Rr]esult*/
45 | [Bb]uild[Ll]og.*
46 |
47 | # NUnit
48 | *.VisualState.xml
49 | TestResult.xml
50 | nunit-*.xml
51 |
52 | # Build Results of an ATL Project
53 | [Dd]ebugPS/
54 | [Rr]eleasePS/
55 | dlldata.c
56 |
57 | # Benchmark Results
58 | BenchmarkDotNet.Artifacts/
59 |
60 | # .NET Core
61 | project.lock.json
62 | project.fragment.lock.json
63 | artifacts/
64 |
65 | # ASP.NET Scaffolding
66 | ScaffoldingReadMe.txt
67 |
68 | # StyleCop
69 | StyleCopReport.xml
70 |
71 | # Files built by Visual Studio
72 | *_i.c
73 | *_p.c
74 | *_h.h
75 | *.ilk
76 | *.meta
77 | *.obj
78 | *.iobj
79 | *.pch
80 | *.pdb
81 | *.ipdb
82 | *.pgc
83 | *.pgd
84 | *.rsp
85 | *.sbr
86 | *.tlb
87 | *.tli
88 | *.tlh
89 | *.tmp
90 | *.tmp_proj
91 | *_wpftmp.csproj
92 | *.log
93 | *.tlog
94 | *.vspscc
95 | *.vssscc
96 | .builds
97 | *.pidb
98 | *.svclog
99 | *.scc
100 |
101 | # Chutzpah Test files
102 | _Chutzpah*
103 |
104 | # Visual C++ cache files
105 | ipch/
106 | *.aps
107 | *.ncb
108 | *.opendb
109 | *.opensdf
110 | *.sdf
111 | *.cachefile
112 | *.VC.db
113 | *.VC.VC.opendb
114 |
115 | # Visual Studio profiler
116 | *.psess
117 | *.vsp
118 | *.vspx
119 | *.sap
120 |
121 | # Visual Studio Trace Files
122 | *.e2e
123 |
124 | # TFS 2012 Local Workspace
125 | $tf/
126 |
127 | # Guidance Automation Toolkit
128 | *.gpState
129 |
130 | # ReSharper is a .NET coding add-in
131 | _ReSharper*/
132 | *.[Rr]e[Ss]harper
133 | *.DotSettings.user
134 |
135 | # TeamCity is a build add-in
136 | _TeamCity*
137 |
138 | # DotCover is a Code Coverage Tool
139 | *.dotCover
140 |
141 | # AxoCover is a Code Coverage Tool
142 | .axoCover/*
143 | !.axoCover/settings.json
144 |
145 | # Coverlet is a free, cross platform Code Coverage Tool
146 | coverage*.json
147 | coverage*.xml
148 | coverage*.info
149 |
150 | # Visual Studio code coverage results
151 | *.coverage
152 | *.coveragexml
153 |
154 | # NCrunch
155 | _NCrunch_*
156 | .*crunch*.local.xml
157 | nCrunchTemp_*
158 |
159 | # MightyMoose
160 | *.mm.*
161 | AutoTest.Net/
162 |
163 | # Web workbench (sass)
164 | .sass-cache/
165 |
166 | # Installshield output folder
167 | [Ee]xpress/
168 |
169 | # DocProject is a documentation generator add-in
170 | DocProject/buildhelp/
171 | DocProject/Help/*.HxT
172 | DocProject/Help/*.HxC
173 | DocProject/Help/*.hhc
174 | DocProject/Help/*.hhk
175 | DocProject/Help/*.hhp
176 | DocProject/Help/Html2
177 | DocProject/Help/html
178 |
179 | # Click-Once directory
180 | publish/
181 |
182 | # Publish Web Output
183 | *.[Pp]ublish.xml
184 | *.azurePubxml
185 | # Note: Comment the next line if you want to checkin your web deploy settings,
186 | # but database connection strings (with potential passwords) will be unencrypted
187 | *.pubxml
188 | *.publishproj
189 |
190 | # Microsoft Azure Web App publish settings. Comment the next line if you want to
191 | # checkin your Azure Web App publish settings, but sensitive information contained
192 | # in these scripts will be unencrypted
193 | PublishScripts/
194 |
195 | # NuGet Packages
196 | *.nupkg
197 | # NuGet Symbol Packages
198 | *.snupkg
199 | # The packages folder can be ignored because of Package Restore
200 | **/[Pp]ackages/*
201 | # except build/, which is used as an MSBuild target.
202 | !**/[Pp]ackages/build/
203 | # Uncomment if necessary however generally it will be regenerated when needed
204 | #!**/[Pp]ackages/repositories.config
205 | # NuGet v3's project.json files produces more ignorable files
206 | *.nuget.props
207 | *.nuget.targets
208 |
209 | # Microsoft Azure Build Output
210 | csx/
211 | *.build.csdef
212 |
213 | # Microsoft Azure Emulator
214 | ecf/
215 | rcf/
216 |
217 | # Windows Store app package directories and files
218 | AppPackages/
219 | BundleArtifacts/
220 | Package.StoreAssociation.xml
221 | _pkginfo.txt
222 | *.appx
223 | *.appxbundle
224 | *.appxupload
225 |
226 | # Visual Studio cache files
227 | # files ending in .cache can be ignored
228 | *.[Cc]ache
229 | # but keep track of directories ending in .cache
230 | !?*.[Cc]ache/
231 |
232 | # Others
233 | ClientBin/
234 | ~$*
235 | *~
236 | *.dbmdl
237 | *.dbproj.schemaview
238 | *.jfm
239 | *.pfx
240 | *.publishsettings
241 | orleans.codegen.cs
242 |
243 | # Including strong name files can present a security risk
244 | # (https://github.com/github/gitignore/pull/2483#issue-259490424)
245 | #*.snk
246 |
247 | # Since there are multiple workflows, uncomment next line to ignore bower_components
248 | # (https://github.com/github/gitignore/pull/1529#issuecomment-104372622)
249 | #bower_components/
250 |
251 | # RIA/Silverlight projects
252 | Generated_Code/
253 |
254 | # Backup & report files from converting an old project file
255 | # to a newer Visual Studio version. Backup files are not needed,
256 | # because we have git ;-)
257 | _UpgradeReport_Files/
258 | Backup*/
259 | UpgradeLog*.XML
260 | UpgradeLog*.htm
261 | ServiceFabricBackup/
262 | *.rptproj.bak
263 |
264 | # SQL Server files
265 | *.mdf
266 | *.ldf
267 | *.ndf
268 |
269 | # Business Intelligence projects
270 | *.rdl.data
271 | *.bim.layout
272 | *.bim_*.settings
273 | *.rptproj.rsuser
274 | *- [Bb]ackup.rdl
275 | *- [Bb]ackup ([0-9]).rdl
276 | *- [Bb]ackup ([0-9][0-9]).rdl
277 |
278 | # Microsoft Fakes
279 | FakesAssemblies/
280 |
281 | # GhostDoc plugin setting file
282 | *.GhostDoc.xml
283 |
284 | # Node.js Tools for Visual Studio
285 | .ntvs_analysis.dat
286 | node_modules/
287 |
288 | # Visual Studio 6 build log
289 | *.plg
290 |
291 | # Visual Studio 6 workspace options file
292 | *.opt
293 |
294 | # Visual Studio 6 auto-generated workspace file (contains which files were open etc.)
295 | *.vbw
296 |
297 | # Visual Studio 6 auto-generated project file (contains which files were open etc.)
298 | *.vbp
299 |
300 | # Visual Studio 6 workspace and project file (working project files containing files to include in project)
301 | *.dsw
302 | *.dsp
303 |
304 | # Visual Studio 6 technical files
305 | *.ncb
306 | *.aps
307 |
308 | # Visual Studio LightSwitch build output
309 | **/*.HTMLClient/GeneratedArtifacts
310 | **/*.DesktopClient/GeneratedArtifacts
311 | **/*.DesktopClient/ModelManifest.xml
312 | **/*.Server/GeneratedArtifacts
313 | **/*.Server/ModelManifest.xml
314 | _Pvt_Extensions
315 |
316 | # Paket dependency manager
317 | .paket/paket.exe
318 | paket-files/
319 |
320 | # FAKE - F# Make
321 | .fake/
322 |
323 | # CodeRush personal settings
324 | .cr/personal
325 |
326 | # Python Tools for Visual Studio (PTVS)
327 | __pycache__/
328 | *.pyc
329 |
330 | # Cake - Uncomment if you are using it
331 | # tools/**
332 | # !tools/packages.config
333 |
334 | # Tabs Studio
335 | *.tss
336 |
337 | # Telerik's JustMock configuration file
338 | *.jmconfig
339 |
340 | # BizTalk build output
341 | *.btp.cs
342 | *.btm.cs
343 | *.odx.cs
344 | *.xsd.cs
345 |
346 | # OpenCover UI analysis results
347 | OpenCover/
348 |
349 | # Azure Stream Analytics local run output
350 | ASALocalRun/
351 |
352 | # MSBuild Binary and Structured Log
353 | *.binlog
354 |
355 | # NVidia Nsight GPU debugger configuration file
356 | *.nvuser
357 |
358 | # MFractors (Xamarin productivity tool) working folder
359 | .mfractor/
360 |
361 | # Local History for Visual Studio
362 | .localhistory/
363 |
364 | # Visual Studio History (VSHistory) files
365 | .vshistory/
366 |
367 | # BeatPulse healthcheck temp database
368 | healthchecksdb
369 |
370 | # Backup folder for Package Reference Convert tool in Visual Studio 2017
371 | MigrationBackup/
372 |
373 | # Ionide (cross platform F# VS Code tools) working folder
374 | .ionide/
375 |
376 | # Fody - auto-generated XML schema
377 | FodyWeavers.xsd
378 |
379 | # VS Code files for those working on multiple tools
380 | .vscode/*
381 | !.vscode/settings.json
382 | !.vscode/tasks.json
383 | !.vscode/launch.json
384 | !.vscode/extensions.json
385 | *.code-workspace
386 |
387 | # Local History for Visual Studio Code
388 | .history/
389 |
390 | # Windows Installer files from build outputs
391 | *.cab
392 | *.msi
393 | *.msix
394 | *.msm
395 | *.msp
396 |
397 | # JetBrains Rider
398 | *.sln.iml
399 |
400 | **/credentials.json
401 | **/appsettings.json
402 | *.dccache
403 | /ApigeeToApimMigrationTool/Properties/launchSettings.json
404 | /ApigeeToApimMigrationTool/apigeeToApimConfig.json
405 |
--------------------------------------------------------------------------------
/.vscode/launch.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "0.2.0",
3 | "configurations": [
4 | {
5 | // Use IntelliSense to find out which attributes exist for C# debugging
6 | // Use hover for the description of the existing attributes
7 | // For further information visit https://github.com/OmniSharp/omnisharp-vscode/blob/master/debugger-launchjson.md
8 | "name": ".NET Core Launch (console)",
9 | "type": "coreclr",
10 | "request": "launch",
11 | "preLaunchTask": "build",
12 | // If you have changed target frameworks, make sure to update the program path.
13 | "program": "${workspaceFolder}/ApigeeToApimMigrationTool/bin/Debug/net6.0/ApigeeToApimMigrationTool.dll",
14 | "args": [],
15 | "cwd": "${workspaceFolder}/ApigeeToApimMigrationTool",
16 | // For more information about the 'console' field, see https://aka.ms/VSCode-CS-LaunchJson-Console
17 | "console": "internalConsole",
18 | "stopAtEntry": false
19 | },
20 | {
21 | "name": ".NET Core Attach",
22 | "type": "coreclr",
23 | "request": "attach"
24 | }
25 | ]
26 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | "version": "2.0.0",
3 | "tasks": [
4 | {
5 | "label": "build",
6 | "command": "dotnet",
7 | "type": "process",
8 | "args": [
9 | "build",
10 | "${workspaceFolder}/ApigeeToApimMigrationTool/ApigeeToApimMigrationTool.csproj",
11 | "/property:GenerateFullPaths=true",
12 | "/consoleloggerparameters:NoSummary"
13 | ],
14 | "problemMatcher": "$msCompile"
15 | },
16 | {
17 | "label": "publish",
18 | "command": "dotnet",
19 | "type": "process",
20 | "args": [
21 | "publish",
22 | "${workspaceFolder}/ApigeeToApimMigrationTool/ApigeeToApimMigrationTool.csproj",
23 | "/property:GenerateFullPaths=true",
24 | "/consoleloggerparameters:NoSummary"
25 | ],
26 | "problemMatcher": "$msCompile"
27 | },
28 | {
29 | "label": "watch",
30 | "command": "dotnet",
31 | "type": "process",
32 | "args": [
33 | "watch",
34 | "run",
35 | "--project",
36 | "${workspaceFolder}/ApigeeToApimMigrationTool/ApigeeToApimMigrationTool.csproj"
37 | ],
38 | "problemMatcher": "$msCompile"
39 | }
40 | ]
41 | }
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.DataAccess/ApigeeToApimMigrationTool.DataAccess.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.DataAccess/ProxyMetaDataDataAccess.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToApimMigrationTool.Core;
2 | using ApigeeToApimMigrationTool.Core.Interface;
3 | using ApigeeToAzureApimMigrationTool.Core.Dto;
4 | using ApigeeToAzureApimMigrationTool.Core.Interface;
5 | using Dapper;
6 | using Microsoft.Data.SqlClient;
7 | using System.IO;
8 |
9 | namespace ApigeeToApimMigrationTool.DataAccess
10 | {
11 |
12 | public class ProxyMetaDataDataAccess : IProxyMetaDataDataAccess
13 | {
14 | private readonly SqlConnection _connection;
15 | public ProxyMetaDataDataAccess(string connectionString)
16 | {
17 | _connection = new SqlConnection(connectionString);
18 | }
19 |
20 | public async Task IsProxyMetadataTablePopulted()
21 | {
22 | bool result = await _connection.QuerySingleOrDefaultAsync("if EXISTS (SELECT 1 FROM Proxy) begin select 1 end else begin select 0 end\r\n");
23 | return result;
24 | }
25 |
26 | public async Task GetProxyRevisionMetaDataByPath(string path)
27 | {
28 | var result = await _connection.QuerySingleOrDefaultAsync($@"select p.Id, p.ProxyName, p.Revision, p.Description from Proxy p
29 | join ProxyBasePath bp on p.Id = bp.ProxyId where bp.Path = '{path}'");
30 | return result;
31 | }
32 |
33 | public async Task InsertProxyRevisionMetaData(ApiProxyRevisionMetadata metaData)
34 | {
35 | if (_connection.State == System.Data.ConnectionState.Closed)
36 | await _connection.OpenAsync();
37 |
38 | SqlTransaction transaction = _connection.BeginTransaction();
39 | try
40 | {
41 | SqlCommand apiProxyInsertCommand = new SqlCommand($@"INSERT INTO [Proxy]([ProxyName],[Revision],[Description])
42 | VALUES (@Name,@Revision, @Description); select SCOPE_IDENTITY()", _connection, transaction);
43 | apiProxyInsertCommand.Parameters.AddWithValue("Name", metaData.Name);
44 | apiProxyInsertCommand.Parameters.AddWithValue("Revision", metaData.Revision);
45 | apiProxyInsertCommand.Parameters.AddWithValue("Description", metaData.Description?? "");
46 | var proxyId = await apiProxyInsertCommand.ExecuteScalarAsync();
47 |
48 | if (proxyId == null)
49 | throw new ArgumentNullException("proxyId", "proxyId is null after inserting the metadata into sql table Proxy");
50 |
51 | foreach (var path in metaData.BasePaths)
52 | {
53 | SqlCommand apiProxyPathInsertCommand = new SqlCommand($"INSERT INTO [ProxyBasePath]([Path],[ProxyId]) VALUES (@Path ,@ProxyId)", _connection, transaction);
54 | apiProxyPathInsertCommand.Parameters.AddWithValue("Path", path?? "");
55 | apiProxyPathInsertCommand.Parameters.AddWithValue("ProxyId", proxyId);
56 | await apiProxyPathInsertCommand.ExecuteNonQueryAsync();
57 | }
58 | foreach (var policy in metaData.Policies)
59 | {
60 | SqlCommand apiProxyPolicyInsertCommand = new SqlCommand($"INSERT INTO [ProxyPolicy]([PolicyName],[ProxyId]) VALUES (@PolicyName ,@ProxyId)", _connection, transaction);
61 | apiProxyPolicyInsertCommand.Parameters.AddWithValue("PolicyName", policy ?? "");
62 | apiProxyPolicyInsertCommand.Parameters.AddWithValue("ProxyId", proxyId);
63 |
64 | await apiProxyPolicyInsertCommand.ExecuteNonQueryAsync();
65 | }
66 | foreach (var endpoint in metaData.ProxyEndpointPaths)
67 | {
68 | SqlCommand apiProxyProxyEndpointsInsertCommand = new SqlCommand($"INSERT INTO [ProxyEndpoint]([ProxyEndpoint],[ProxyId],[EndpointName]) VALUES (@ProxyEndpoint ,@ProxyId, @EndpointName)", _connection, transaction);
69 | apiProxyProxyEndpointsInsertCommand.Parameters.AddWithValue("EndpointName", endpoint.Key ?? "");
70 | apiProxyProxyEndpointsInsertCommand.Parameters.AddWithValue("ProxyEndpoint", endpoint.Value ?? "");
71 | apiProxyProxyEndpointsInsertCommand.Parameters.AddWithValue("ProxyId", proxyId);
72 | await apiProxyProxyEndpointsInsertCommand.ExecuteNonQueryAsync();
73 | }
74 |
75 | await transaction.CommitAsync();
76 | }
77 | catch (Exception)
78 | {
79 | await transaction.RollbackAsync();
80 | throw;
81 | }
82 | }
83 | }
84 | }
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Database/ApigeeToApimMigrationTool.Database.sqlproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Debug
5 | AnyCPU
6 | ApigeeToApimMigrationTool.Database
7 | 2.0
8 | 4.1
9 | {0fb5c73e-88dd-44de-9dd5-882d6de57189}
10 | Microsoft.Data.Tools.Schema.Sql.SqlAzureV12DatabaseSchemaProvider
11 | Database
12 |
13 |
14 | ApigeeToApimMigrationTool.Database
15 | ApigeeToApimMigrationTool.Database
16 | 1033, CI
17 | BySchemaAndSchemaType
18 | True
19 | v4.7.2
20 | CS
21 | Properties
22 | False
23 | True
24 | True
25 |
26 |
27 | bin\Release\
28 | $(MSBuildProjectName).sql
29 | False
30 | pdbonly
31 | true
32 | false
33 | true
34 | prompt
35 | 4
36 |
37 |
38 | bin\Debug\
39 | $(MSBuildProjectName).sql
40 | false
41 | true
42 | full
43 | false
44 | true
45 | true
46 | prompt
47 | 4
48 |
49 |
50 | 11.0
51 |
52 | True
53 | 11.0
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Database/StoredProcedures/DeleteAllData.sql:
--------------------------------------------------------------------------------
1 | CREATE PROCEDURE [dbo].[DeleteAllData]
2 | AS
3 | delete from ProxyPolicy
4 | delete from ProxyBasePath
5 | delete from ProxyEndpoint
6 | delete from Proxy
7 | RETURN 0
8 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Database/Tables/Proxy.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE [dbo].[Proxy](
2 | [Id] [int] IDENTITY(1,1) NOT NULL,
3 | [ProxyName] [varchar](150) NOT NULL,
4 | [Revision] [smallint] NOT NULL,
5 | [Description] [varchar](1000) NULL,
6 | CONSTRAINT [PK_Proxy] PRIMARY KEY CLUSTERED
7 | (
8 | [Id] ASC
9 | )WITH (PAD_INDEX = OFF, STATISTICS_NORECOMPUTE = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS = ON, ALLOW_PAGE_LOCKS = ON, OPTIMIZE_FOR_SEQUENTIAL_KEY = OFF) ON [PRIMARY]
10 | ) ON [PRIMARY]
11 | GO
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Database/Tables/ProxyBasePath.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE [dbo].[ProxyBasePath]
2 | (
3 | [Id] INT NOT NULL PRIMARY KEY IDENTITY,
4 | [Path] VARCHAR(1000) NOT NULL,
5 | [ProxyId] INT NOT NULL,
6 | CONSTRAINT [FK_ProxyBasePath_ToProxy] FOREIGN KEY ([ProxyId]) REFERENCES [Proxy]([Id])
7 | )
8 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Database/Tables/ProxyEndpoint.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE [dbo].[ProxyEndpoint]
2 | (
3 | [Id] INT NOT NULL PRIMARY KEY IDENTITY,
4 | [ProxyEndpoint] VARCHAR(100) NOT NULL,
5 | [ProxyId] INT NOT NULL,
6 | [EndpointName] NVARCHAR(100) NOT NULL,
7 | CONSTRAINT [FK_ProxyEndpoint_ToProxy] FOREIGN KEY ([ProxyId]) REFERENCES [Proxy]([Id])
8 | )
9 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Database/Tables/ProxyPolicy.sql:
--------------------------------------------------------------------------------
1 | CREATE TABLE [dbo].[ProxyPolicy]
2 | (
3 | [Id] INT NOT NULL PRIMARY KEY IDENTITY,
4 | [PolicyName] VARCHAR(100) NOT NULL,
5 | [ProxyId] INT NOT NULL,
6 | CONSTRAINT [FK_ProxyPolicy_ToProxy] FOREIGN KEY ([ProxyId]) REFERENCES [Proxy]([Id])
7 | )
8 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Test/ApigeeToApimMigrationTool.Test.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 | enable
7 |
8 | false
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 | runtime; build; native; contentfiles; analyzers; buildtransitive
17 | all
18 |
19 |
20 | runtime; build; native; contentfiles; analyzers; buildtransitive
21 | all
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 | Always
33 |
34 |
35 | Always
36 |
37 |
38 | Always
39 |
40 |
41 | Always
42 |
43 |
44 | Always
45 |
46 |
47 | Always
48 |
49 |
50 | Always
51 |
52 |
53 | Always
54 |
55 |
56 |
57 |
58 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Test/AzureApimServiceTest.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToApimMigrationTool.Core.Config;
2 | using ApigeeToAzureApimMigrationTool.Core;
3 | using ApigeeToAzureApimMigrationTool.Core.Dto;
4 | using ApigeeToAzureApimMigrationTool.Core.Interface;
5 | using ApigeeToAzureApimMigrationTool.Service;
6 | using ApigeeToAzureApimMigrationTool.Service.Transformations;
7 | using Newtonsoft.Json;
8 | using System.Reflection;
9 | using System.Xml.Linq;
10 |
11 | namespace ApigeeToApimMigrationTool.Test
12 | {
13 | public class AzureApimServiceTest
14 | {
15 | private IAzureApimService _azureApimServiceUnderTest;
16 |
17 | // Dependencies
18 | private readonly MockApigeeManagementApiService _mockApigeeManagementApiService;
19 | private readonly MockApigeeXmlLoader _mockApigeeXmlLoader;
20 | private readonly MockApimProvider _mockApimProvider;
21 | private readonly MockBundleProvider _mockBundleProvider;
22 | private readonly IExpressionTranslator _expressionTranslator;
23 |
24 | public AzureApimServiceTest()
25 | {
26 | _mockApigeeManagementApiService = new MockApigeeManagementApiService();
27 | _mockApigeeXmlLoader = new MockApigeeXmlLoader();
28 | _mockApimProvider = new MockApimProvider();
29 | _mockBundleProvider = new MockBundleProvider();
30 | _expressionTranslator = new ExpressionTranslator();
31 |
32 | // We need a real transformation factory and transformer here because we are testing the integration between the service
33 | // and the transformer
34 | var policyTransformationFactory = new PolicyTransformationFactory(
35 | _mockApigeeManagementApiService, _mockApimProvider, _mockBundleProvider, _mockApigeeXmlLoader, _expressionTranslator);
36 |
37 | var policyTransformer = new ApigeeToApimPolicyTransformer(policyTransformationFactory, _mockApimProvider, _expressionTranslator);
38 |
39 | _azureApimServiceUnderTest = new AzureApimService(
40 | apimProvider: _mockApimProvider,
41 | apigeeXmlLoader: _mockApigeeXmlLoader,
42 | policyTransformer: policyTransformer,
43 | expressionTranslator: _expressionTranslator);
44 |
45 | SetupDefaultPolicies();
46 | }
47 |
48 | [Fact]
49 | public async Task AssignMessagePolicy_InRequestPreFlow_WithSetHeader_SetsApimHeader_InInbound()
50 | {
51 | XElement testPolicyElement = XElement.Parse(@"test-policy");
52 | XElement? preFlowPolicyElement = _mockApigeeXmlLoader.ProxyEndpointXml["default"].Element("ProxyEndpoint")?.Element("PreFlow");
53 |
54 | Assert.NotNull(preFlowPolicyElement);
55 | preFlowPolicyElement?.Add(testPolicyElement);
56 |
57 | _mockApigeeXmlLoader.PolicyXml.Add("test-policy", XDocument.Parse(
58 | @"
59 |
60 | Set Header
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 | true
69 |
70 | "));
71 |
72 | await _azureApimServiceUnderTest.ImportApi(
73 | apimName: "testApi",
74 | proxyName: "Test-Api",
75 | apimConfiguration: new ApimConfiguration(),
76 | apigeeConfiguration: new ApigeeConfiguration(),
77 | keyVaultName: string.Empty);
78 |
79 | var policy = _mockApimProvider.PolicyXml;
80 |
81 | XElement? setHeaderPolicy = policy?.Element("policies")?.Element("inbound")?.Element("set-header");
82 | Assert.NotNull(setHeaderPolicy);
83 | Assert.Equal("test-header", setHeaderPolicy?.Attribute("name")?.Value);
84 | Assert.Equal("test-value", setHeaderPolicy?.Element("value")?.Value);
85 |
86 | }
87 |
88 | private void SetupDefaultPolicies()
89 | {
90 | _mockApigeeXmlLoader.ProxyXml.Add("Test-Api", XDocument.Parse(
91 | @"
92 |
93 | /test
94 | Test API
95 | Test-API
96 |
97 | test-policy
98 |
99 |
100 | default
101 |
102 |
103 |
104 |
105 |
106 | default
107 |
108 | "));
109 |
110 | _mockApigeeXmlLoader.ProxyEndpointXml.Add("default", XDocument.Parse(
111 | @"
112 |
113 |
114 |
115 |
116 |
117 | /test
118 |
119 |
120 | default
121 |
122 | "));
123 |
124 | _mockApigeeXmlLoader.TargetXml.Add("default", XDocument.Parse(
125 | @"
126 |
127 |
128 |
129 |
130 |
131 | https://test.example.com
132 |
133 | "));
134 | }
135 | }
136 | }
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Test/AzureSdkMocks/MockApiManagementProductResource.cs:
--------------------------------------------------------------------------------
1 | using Azure.ResourceManager.ApiManagement;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace ApigeeToApimMigrationTool.Test.AzureSdkMocks
9 | {
10 | public class MockApiManagementProductResource : ApiManagementProductResource
11 | {
12 | public MockApiManagementProductResource()
13 | {
14 |
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Test/AzureSdkMocks/MockApiResource.cs:
--------------------------------------------------------------------------------
1 | using Azure.ResourceManager.ApiManagement;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace ApigeeToApimMigrationTool.Test.AzureSdkMocks
9 | {
10 | public class MockApiResource : ApiResource
11 | {
12 | public MockApiResource()
13 | {
14 |
15 | }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Test/BundleLoaderTests.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core;
2 | using ApigeeToAzureApimMigrationTool.Core.Interface;
3 | using ApigeeToAzureApimMigrationTool.Service;
4 | using ApigeeToAzureApimMigrationTool.Service.Bundles;
5 | using ApigeeToAzureApimMigrationTool.Service.Transformations;
6 | using System;
7 | using System.Collections.Generic;
8 | using System.Linq;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 |
12 | namespace ApigeeToApimMigrationTool.Test
13 | {
14 | public class BundleLoaderTests
15 | {
16 | // The purpose of these tests is to test loading bundles from files.
17 | // We're using the test file loaders, but the process should be the same
18 | // with the real loaders, only we'll be loading from the filesystem instead
19 | // of from the Apigee API.
20 |
21 | private readonly AzureApimService _azureApimServiceUnderTest;
22 | private readonly IBundleProvider _bundleProvider;
23 | private readonly MockApimProvider _apimProvider;
24 | private readonly IExpressionTranslator _expressionTranslator;
25 |
26 | public BundleLoaderTests()
27 | {
28 | var testConfigPath = "TestBundles";
29 |
30 | _bundleProvider = new ApigeeFileBundleProvider(testConfigPath);
31 | _apimProvider = new MockApimProvider();
32 | _expressionTranslator = new ExpressionTranslator();
33 |
34 |
35 | IApigeeXmlLoader apigeeXmlLoader = new ApigeeXmlFileLoader(_bundleProvider);
36 | IExpressionTranslator expressionTranslator = new ExpressionTranslator();
37 | IApigeeManagementApiService apigeeManagementApiService = new ApigeeManagementApiTestFileService(_bundleProvider, apigeeXmlLoader, testConfigPath);
38 | IPolicyTransformationFactory policyTransformationFactory = new PolicyTransformationFactory(apigeeManagementApiService, _apimProvider, _bundleProvider, apigeeXmlLoader, expressionTranslator);
39 |
40 | _azureApimServiceUnderTest = new AzureApimService(
41 | apigeeXmlLoader: apigeeXmlLoader,
42 | apimProvider: _apimProvider,
43 | expressionTranslator: _expressionTranslator,
44 | policyTransformer: new ApigeeToApimPolicyTransformer(policyTransformationFactory, _apimProvider, _expressionTranslator));
45 | }
46 | [Fact]
47 | public async Task FileBundleLoader_WithSharedFlowPolicy_LoadsSharedFlow()
48 | {
49 | var bundle = _bundleProvider.GetApiProxyBundle("Test-API");
50 | await bundle.LoadBundle();
51 | await _azureApimServiceUnderTest.ImportApi("Test-Apim", "Test-API", null, null, null);
52 |
53 | // GetSharedFlow is a shared flow that is used by the Test-API proxy
54 | Assert.True(_apimProvider.PolicyFragments.ContainsKey("GetSharedFlow"));
55 |
56 | }
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Test/MockApigeeManagementApiService.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core;
2 | using ApigeeToAzureApimMigrationTool.Core.dto;
3 | using ApigeeToAzureApimMigrationTool.Core.Dto;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 |
10 | namespace ApigeeToApimMigrationTool.Test
11 | {
12 | public class MockApigeeManagementApiService : IApigeeManagementApiService
13 | {
14 |
15 | public string AuthenticationToken { get; set; }
16 | public string Username { get; set; }
17 | public string Password { get; set; }
18 |
19 | public string? Environment { get; private set; }
20 |
21 | public string ProxyName { get; set; }
22 |
23 | public Task DownloadApiProxyBundle(string basePath, string proxyName, int revision)
24 |
25 | {
26 | return Task.FromResult(string.Empty);
27 | }
28 |
29 | public Task DownloadSharedFlowBundle(string basePath, string sharedFlowName, int revision)
30 | {
31 | return Task.FromResult(string.Empty);
32 | }
33 |
34 | public Task GetApiProductByName(string productName)
35 | {
36 | var apiProduct = new ApiProductMetaData
37 | {
38 | Name = productName,
39 | DisplayName = productName,
40 | Description = "test",
41 | Proxies = new string[] { "test" }
42 | };
43 |
44 | return Task.FromResult(apiProduct);
45 | }
46 |
47 | public Task GetApiProxyByName(string proxyName)
48 | {
49 | var apiProxy = new ApigeeEntityModel
50 | {
51 | name = proxyName,
52 | revision = new string[] { "1" },
53 | metaData = new ApiProxyMetaData
54 | {
55 | createdAt = 0,
56 | createdBy = "test",
57 | lastModifiedAt = 0,
58 | lastModifiedBy = "test",
59 | subType = "test"
60 | },
61 | };
62 |
63 | return Task.FromResult(apiProxy);
64 | }
65 |
66 | public Task GetAuthenticationToken(string oneTimeToken, string authenticationBaseUrl)
67 | {
68 | return Task.FromResult(string.Empty);
69 | }
70 |
71 | public Task GetAuthenticationToken(string username, string password, string authenticationBaseUrl)
72 | {
73 | return Task.FromResult(string.Empty);
74 | }
75 |
76 | public Task GetKeyValueMapByName(string proxyName, string environment, string mapIdentifier)
77 | {
78 | var keyMap = new KeyValueMapModel
79 | {
80 | Name = mapIdentifier,
81 | Encrypted = false,
82 | Entry = new KeyValueMapItemModel[]
83 | {
84 | new KeyValueMapItemModel
85 | {
86 | Name = "test",
87 | Value = "test"
88 | }
89 | }
90 | };
91 |
92 | return Task.FromResult(keyMap);
93 |
94 | }
95 |
96 | public Task GetSharedFlowByName(string sharedFlowName)
97 | {
98 | var sharedFlow = new ApigeeEntityModel { name = sharedFlowName, revision = new string[] { "1" } };
99 | return Task.FromResult(sharedFlow);
100 | }
101 |
102 | public Task GetTargetServerByName(string targetServerName, string environment)
103 | {
104 | var targetServer = new ApigeeTargetServerModel
105 | {
106 | Name = targetServerName,
107 | Host = "test",
108 | Port = 443,
109 | IsEnabled = true,
110 | SSLInfo = new ApigeeTargetServerSSLInfo
111 | {
112 | Ciphers = new string[] { "test" },
113 | ClientAuthEnabled = true,
114 | Enabled = true,
115 | IgnoreValidationError = true,
116 | Protocols = new string[] { "test" },
117 | TrustStore = "test"
118 | }
119 | };
120 |
121 | return Task.FromResult(targetServer);
122 | }
123 |
124 | public Task PopulateProxyReferenceDatabase()
125 | {
126 | return Task.CompletedTask;
127 | }
128 | }
129 | }
130 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Test/MockApigeeXmlLoader.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core.Interface;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Xml.Linq;
8 |
9 | namespace ApigeeToApimMigrationTool.Test
10 | {
11 | public class MockApigeeXmlLoader : IApigeeXmlLoader
12 | {
13 | public Dictionary PolicyXml { get; set; } = new Dictionary();
14 | public Dictionary ProxyEndpointXml { get; set; } = new Dictionary();
15 | public Dictionary ProxyXml { get; set; } = new Dictionary();
16 | public Dictionary SharedFlowBundleXml { get; set; } = new Dictionary();
17 | public Dictionary SharedFlowPolicyXml { get; set; } = new Dictionary();
18 | public Dictionary SharedFlowXml { get; set; } = new Dictionary();
19 | public Dictionary TargetXml { get; set; } = new Dictionary();
20 |
21 | public XDocument LoadPolicyXml(string proxyName, string policyName)
22 | {
23 | if (PolicyXml.ContainsKey(policyName))
24 | {
25 | return PolicyXml[policyName];
26 | }
27 | else
28 | {
29 | return new XDocument();
30 | }
31 | }
32 |
33 | public XDocument LoadProxyEndpointXml(string proxyName, string proxyEndpointName)
34 | {
35 | if (ProxyEndpointXml.ContainsKey(proxyEndpointName))
36 | {
37 | return ProxyEndpointXml[proxyEndpointName];
38 | }
39 | else
40 | {
41 | return new XDocument();
42 | }
43 | }
44 |
45 | public XDocument LoadProxyXml(string proxyName)
46 | {
47 | if (ProxyXml.ContainsKey(proxyName))
48 | {
49 | return ProxyXml[proxyName];
50 | }
51 | else
52 | {
53 | return new XDocument();
54 | }
55 | }
56 |
57 | public XDocument LoadSharedFlowBundleXml(string sharedFlowName)
58 | {
59 | if (SharedFlowBundleXml.ContainsKey(sharedFlowName))
60 | {
61 | return SharedFlowBundleXml[sharedFlowName];
62 | }
63 | else
64 | {
65 | return new XDocument();
66 | }
67 | }
68 |
69 | public XDocument LoadSharedFlowPolicyXml(string sharedFlowName, string policyName)
70 | {
71 | if (SharedFlowPolicyXml.ContainsKey(policyName))
72 | {
73 | return SharedFlowPolicyXml[policyName];
74 | }
75 | else
76 | {
77 | return new XDocument();
78 | }
79 | }
80 |
81 | public XDocument LoadSharedFlowXml(string sharedFlowName, string sharedFlowFileName)
82 | {
83 | if (SharedFlowXml.ContainsKey(sharedFlowName))
84 | {
85 | return SharedFlowXml[sharedFlowName];
86 | }
87 | else
88 | {
89 | return new XDocument();
90 | }
91 | }
92 |
93 | public XDocument LoadTargetXml(string proxyName, string targetEndpointName)
94 | {
95 | if (TargetXml.ContainsKey(targetEndpointName))
96 | {
97 | return TargetXml[targetEndpointName];
98 | }
99 | else
100 | {
101 | return new XDocument();
102 | }
103 | }
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Test/MockApimProvider.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToApimMigrationTool.Test.AzureSdkMocks;
2 | using ApigeeToAzureApimMigrationTool.Core.Interface;
3 | using Azure.ResourceManager.ApiManagement;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Xml.Linq;
10 |
11 | namespace ApigeeToApimMigrationTool.Test
12 | {
13 | public class MockApimProvider : IApimProvider
14 | {
15 | public string ApimName { get; set; }
16 | public string ApimUrl { get; set; }
17 | public XDocument PolicyXml { get; private set; } = new XDocument();
18 | public IDictionary PolicyFragments { get; private set; } = new Dictionary();
19 |
20 | public Task AddApiToProduct(string apiId)
21 | {
22 | return Task.CompletedTask;
23 | }
24 |
25 | public Task AddNamedValue(string apimName, string proxyName, string mapIdentifier, string keyName, bool isSecret, string value, int index)
26 | {
27 | return Task.CompletedTask;
28 | }
29 |
30 | public Task CreateApi(string apiName, string apiDisplayName, string apiDescription, string apimName, string revision, string apiPath, string backendUrl, string? oauthConfigurationName)
31 | {
32 | var mockResource = new MockApiResource();
33 | return Task.FromResult(mockResource as ApiResource);
34 | }
35 |
36 | public Task CreateOrUpdateOperation(string apiName, string description, string httpVerb)
37 | {
38 | return Task.CompletedTask;
39 | }
40 |
41 | public Task CreateOrUpdateOperationPolicy(XDocument operationPolicyXml, string operationName, string operationDescription, string httpVerb, string proxyPath)
42 | {
43 | return Task.CompletedTask;
44 | }
45 |
46 | public Task CreatePolicy(XDocument policyXml)
47 | {
48 | PolicyXml = policyXml;
49 | return Task.CompletedTask;
50 | }
51 |
52 | public Task CreatePolicyFragment(string policyFragmentName, string apimName, string policyFragmentXml, string policyFragmentDescription)
53 | {
54 | PolicyFragments.Add(policyFragmentName, XDocument.Parse(policyFragmentXml));
55 | return Task.CompletedTask;
56 | }
57 |
58 | public Task CreateProduct(string name, string displayName, string description, string apimName)
59 | {
60 | var mockProduct = new MockApiManagementProductResource();
61 | return Task.FromResult(mockProduct as ApiManagementProductResource);
62 | }
63 |
64 | public string RemoveTrailingSpecialCharacters(string input)
65 | {
66 | throw new NotImplementedException();
67 | }
68 |
69 | public Task UpdateApiSubscriptionSetting(string apimName, string proxyName, string headerName = "", string queryParameterName = "")
70 | {
71 | return Task.CompletedTask;
72 | }
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Test/MockBundleProvider.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core.Interface;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace ApigeeToApimMigrationTool.Test
9 | {
10 | public class MockBundleProvider : IBundleProvider
11 | {
12 | public IBundle GetApiProxyBundle(string proxyOrProductName)
13 | {
14 | throw new NotImplementedException();
15 | }
16 |
17 | public IBundle GetSharedFlowBundle(string sharedFlowName)
18 | {
19 | throw new NotImplementedException();
20 | }
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Test/MockPolicyTransformer.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToApimMigrationTool.Core.Config;
2 | using ApigeeToAzureApimMigrationTool.Core.Interface;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Xml.Linq;
9 |
10 | namespace ApigeeToApimMigrationTool.Test
11 | {
12 | public class MockPolicyTransformer : IApimPolicyTransformer
13 | {
14 | public Task TransformPoliciesInCollection(IEnumerable? elements, XElement azureApimPolicySection, Func xmlLoader,
15 | string apimName, string proxyName, ApigeeConfiguration apigeeConfiguration, ApimConfiguration apimConfig)
16 | {
17 | throw new NotImplementedException();
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Test/TestBundles/GetSharedFlow/sharedflowbundle/GetSharedFlow.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 1513011664744
5 | jaspecla@microsoft.com
6 | Test Shared Flow
7 | GetSharedFlow
8 | 1634053049817
9 | jaspecla@microsoft.com
10 |
11 | Get-Shared-Flow
12 |
13 |
14 |
15 | SharedFlow
16 |
17 | default
18 |
19 |
20 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Test/TestBundles/GetSharedFlow/sharedflowbundle/policies/Get-Shared-Flow.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Get Shared Flow
4 | 3600
5 | environment
6 |
7 |
8 | MyKey
9 |
10 |
11 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Test/TestBundles/GetSharedFlow/sharedflowbundle/sharedflows/default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Get-Shared-Flow
5 |
6 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Test/TestBundles/Test-API/apiproxy/Test-API.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | /profile
4 |
5 | 1554751795786
6 | jaspecla@microsoft.com
7 | Test API
8 | Test-API
9 | 1645821267509
10 | jaspecla@microsoft.com
11 |
12 | SharedFlowCallout
13 |
14 |
15 | default
16 |
17 |
18 |
19 |
20 |
21 | default
22 |
23 |
24 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Test/TestBundles/Test-API/apiproxy/policies/SharedFlowCallout.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | SahredFlowCallout
4 |
5 |
6 | GetSharedFlow
7 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Test/TestBundles/Test-API/apiproxy/proxies/default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 | /profile
15 |
16 |
17 |
18 | default
19 |
20 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Test/TestBundles/Test-API/apiproxy/targets/default.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | SharedFlowCallout
9 |
10 |
11 |
12 |
13 |
14 |
15 | 180000
16 |
17 | https://SetInDynamicUrlSharedflow
18 |
19 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Test/TransformationTests/AssignMessageTransformationTests.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Service;
2 | using ApigeeToAzureApimMigrationTool.Service.Transformations;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Xml.Linq;
9 |
10 | namespace ApigeeToApimMigrationTool.Test.TransformationTests
11 | {
12 | public class AssignMessageTransformationTests
13 | {
14 | [Fact]
15 | public async Task Transform_AddHeaderPolicy_AddsHeader()
16 | {
17 | // Arrange
18 | var apigeePolicyElement = XElement.Parse(
19 | @"
20 |
21 |
22 |
23 |
24 |
25 | ");
26 |
27 | var apigeePolicyName = "Add-Header-1";
28 |
29 | var sut = new AssignMessageTransformation(new ExpressionTranslator());
30 |
31 | // Act
32 | var result = await sut.Transform(apigeePolicyElement, apigeePolicyName);
33 |
34 | // Assert
35 | Assert.Single(result);
36 | Assert.Equal("set-header", result.First().Name.LocalName);
37 | Assert.Equal("header-1", result.First().Attribute("name").Value);
38 | Assert.Equal("value-1", result.First().Element("value").Value);
39 | }
40 |
41 | [Fact]
42 | public async Task Transform_SetHeaderPolicy_AddsHeader()
43 | {
44 | // Arrange
45 | var apigeePolicyElement = XElement.Parse(
46 | @"
47 |
48 |
49 |
50 |
51 |
52 | ");
53 |
54 | var apigeePolicyName = "Set-Header-1";
55 |
56 | var sut = new AssignMessageTransformation(new ExpressionTranslator());
57 |
58 | // Act
59 | var result = await sut.Transform(apigeePolicyElement, apigeePolicyName);
60 |
61 | // Assert
62 | Assert.Single(result);
63 | Assert.Equal("set-header", result.First().Name.LocalName);
64 | Assert.Equal("override", result.First().Attribute("exists-action").Value);
65 | Assert.Equal("header-1", result.First().Attribute("name").Value);
66 | Assert.Equal("value-1", result.First().Element("value").Value);
67 | }
68 |
69 | [Fact]
70 | public async Task Transform_RemoveHeaderPolicy_RemovesHeader()
71 | {
72 | // Arrange
73 | var apigeePolicyElement = XElement.Parse(
74 | @"
75 |
76 |
77 |
78 |
79 |
80 | ");
81 |
82 | var apigeePolicyName = "Remove-Header-1";
83 |
84 | var sut = new AssignMessageTransformation(new ExpressionTranslator());
85 |
86 | // Act
87 | var result = await sut.Transform(apigeePolicyElement, apigeePolicyName);
88 |
89 | // Assert
90 | Assert.Single(result);
91 | Assert.Equal("set-header", result.First().Name.LocalName);
92 | Assert.Equal("delete", result.First().Attribute("exists-action").Value);
93 | Assert.Equal("header-1", result.First().Attribute("name").Value);
94 | }
95 |
96 | [Fact]
97 | public async Task Transform_SetPayloadPolicyWithJson_SetsJsonBody()
98 | {
99 | // Arrange
100 | var apigeePolicyElement = XElement.Parse(
101 | @"
102 |
103 |
104 | {""key"":""value""}
105 |
106 |
107 | ");
108 |
109 | var apigeePolicyName = "Set-Body-1";
110 |
111 | var sut = new AssignMessageTransformation(new ExpressionTranslator());
112 |
113 | // Act
114 | var result = await sut.Transform(apigeePolicyElement, apigeePolicyName);
115 |
116 | // Assert
117 | Assert.Single(result);
118 | Assert.Equal("set-body", result.First().Name.LocalName);
119 | Assert.Equal("{\"key\":\"value\"}", result.First().Value);
120 | }
121 |
122 | [Fact]
123 | public async Task Transform_AssignVariable_SetsVariable()
124 | {
125 | // Arrange
126 | var apigeePolicyElement = XElement.Parse(
127 | @"
128 |
129 | variable-1
130 | value-1
131 |
132 | ");
133 |
134 | var apigeePolicyName = "Assign-Variable-1";
135 |
136 | var sut = new AssignMessageTransformation(new ExpressionTranslator());
137 |
138 | // Act
139 | var result = await sut.Transform(apigeePolicyElement, apigeePolicyName);
140 |
141 | // Assert
142 | Assert.Single(result);
143 | Assert.Equal("set-variable", result.First().Name.LocalName);
144 | Assert.Equal("variable-1", result.First().Attribute("name").Value);
145 | Assert.Equal("value-1", result.First().Attribute("value").Value);
146 | }
147 |
148 | [Fact]
149 | public async Task Transform_AssignVariableWithTemplate_SetsTemplatedVariable()
150 | {
151 | // Arrange
152 | var apigeePolicyElement = XElement.Parse(
153 | @"
154 |
155 | variable-1
156 | {request.verb}
157 |
158 | ");
159 |
160 | var apigeePolicyName = "Assign-Variable-1";
161 |
162 | var sut = new AssignMessageTransformation(new ExpressionTranslator());
163 |
164 | // Act
165 | var result = await sut.Transform(apigeePolicyElement, apigeePolicyName);
166 |
167 | // Assert
168 | Assert.Single(result);
169 | Assert.Equal("set-variable", result.First().Name.LocalName);
170 | Assert.Equal("variable-1", result.First().Attribute("name").Value);
171 | Assert.Equal("@(context.Operation.Method)", result.First().Attribute("value").Value);
172 |
173 | }
174 |
175 | [Fact]
176 | public async Task Transform_AssignVariableWithComplexTemplate_SetsTemplatedVariable()
177 | {
178 | // Arrange
179 | var apigeePolicyElement = XElement.Parse(
180 | @"
181 |
182 | variable-1
183 | {request.verb}/{request.header.origin}
184 |
185 | ");
186 |
187 | var apigeePolicyName = "Assign-Variable-1";
188 |
189 | var sut = new AssignMessageTransformation(new ExpressionTranslator());
190 |
191 | // Act
192 | var result = await sut.Transform(apigeePolicyElement, apigeePolicyName);
193 |
194 | // Assert
195 | Assert.Single(result);
196 | Assert.Equal("set-variable", result.First().Name.LocalName);
197 | Assert.Equal("variable-1", result.First().Attribute("name").Value);
198 | Assert.Equal("@(context.Operation.Method + \"/\" + context.Request.Headers.GetValueOrDefault(\"origin\"))", result.First().Attribute("value").Value);
199 |
200 | }
201 |
202 | [Fact]
203 | public async Task Transform_AssignVariableWithRefAndValue_SetsRefValueOrDefault()
204 | {
205 | // Arrange
206 | var apigeePolicyElement = XElement.Parse(
207 | @"
208 |
209 | variable-1
210 | my-default-value
211 | [request.verb]
212 |
213 | ");
214 |
215 | var apigeePolicyName = "Assign-Variable-1";
216 |
217 | var sut = new AssignMessageTransformation(new ExpressionTranslator());
218 |
219 | // Act
220 | var result = await sut.Transform(apigeePolicyElement, apigeePolicyName);
221 |
222 | // Assert
223 | Assert.Single(result);
224 | Assert.Equal("set-variable", result.First().Name.LocalName);
225 | Assert.Equal("variable-1", result.First().Attribute("name").Value);
226 | Assert.Equal("@(context.Operation.Method ? context.Operation.Method : \"my-default-value\")", result.First().Attribute("value").Value);
227 |
228 | }
229 |
230 |
231 | }
232 | }
233 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.Test/Usings.cs:
--------------------------------------------------------------------------------
1 | global using Xunit;
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio Version 17
4 | VisualStudioVersion = 17.5.33516.290
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApigeeToApimMigrationTool", "ApigeeToApimMigrationTool\ApigeeToApimMigrationTool.csproj", "{A05BB193-76E0-4850-A369-EAA8F223BB3F}"
7 | EndProject
8 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApigeeToAzureApimMigrationTool.Service", "ApigeeToAzureApimMigrationTool.Logic\ApigeeToAzureApimMigrationTool.Service.csproj", "{7892713C-5601-475B-AEB8-D36EF3E313F3}"
9 | EndProject
10 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApigeeToAzureApimMigrationTool.Core", "ApigeeToAzureApimMigrationTool.Core\ApigeeToAzureApimMigrationTool.Core.csproj", "{91FF11ED-58E1-4021-AE1E-BDFA552C550B}"
11 | EndProject
12 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApigeeToApimMigrationTool.Test", "ApigeeToApimMigrationTool.Test\ApigeeToApimMigrationTool.Test.csproj", "{47FC9070-F20E-450A-9567-62753B34BFDC}"
13 | EndProject
14 | Project("{00D1A9C2-B5F0-4AF3-8072-F6C62B433612}") = "ApigeeToApimMigrationTool.Database", "ApigeeToApimMigrationTool.Database\ApigeeToApimMigrationTool.Database.sqlproj", "{0FB5C73E-88DD-44DE-9DD5-882D6DE57189}"
15 | EndProject
16 | Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ApigeeToApimMigrationTool.DataAccess", "ApigeeToApimMigrationTool.DataAccess\ApigeeToApimMigrationTool.DataAccess.csproj", "{871A0F9B-294C-4DAA-8FE1-7B2E37D14DFA}"
17 | EndProject
18 | Global
19 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
20 | Debug|Any CPU = Debug|Any CPU
21 | Release|Any CPU = Release|Any CPU
22 | EndGlobalSection
23 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
24 | {A05BB193-76E0-4850-A369-EAA8F223BB3F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
25 | {A05BB193-76E0-4850-A369-EAA8F223BB3F}.Debug|Any CPU.Build.0 = Debug|Any CPU
26 | {A05BB193-76E0-4850-A369-EAA8F223BB3F}.Release|Any CPU.ActiveCfg = Release|Any CPU
27 | {A05BB193-76E0-4850-A369-EAA8F223BB3F}.Release|Any CPU.Build.0 = Release|Any CPU
28 | {7892713C-5601-475B-AEB8-D36EF3E313F3}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
29 | {7892713C-5601-475B-AEB8-D36EF3E313F3}.Debug|Any CPU.Build.0 = Debug|Any CPU
30 | {7892713C-5601-475B-AEB8-D36EF3E313F3}.Release|Any CPU.ActiveCfg = Release|Any CPU
31 | {7892713C-5601-475B-AEB8-D36EF3E313F3}.Release|Any CPU.Build.0 = Release|Any CPU
32 | {91FF11ED-58E1-4021-AE1E-BDFA552C550B}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
33 | {91FF11ED-58E1-4021-AE1E-BDFA552C550B}.Debug|Any CPU.Build.0 = Debug|Any CPU
34 | {91FF11ED-58E1-4021-AE1E-BDFA552C550B}.Release|Any CPU.ActiveCfg = Release|Any CPU
35 | {91FF11ED-58E1-4021-AE1E-BDFA552C550B}.Release|Any CPU.Build.0 = Release|Any CPU
36 | {47FC9070-F20E-450A-9567-62753B34BFDC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
37 | {47FC9070-F20E-450A-9567-62753B34BFDC}.Debug|Any CPU.Build.0 = Debug|Any CPU
38 | {47FC9070-F20E-450A-9567-62753B34BFDC}.Release|Any CPU.ActiveCfg = Release|Any CPU
39 | {47FC9070-F20E-450A-9567-62753B34BFDC}.Release|Any CPU.Build.0 = Release|Any CPU
40 | {0FB5C73E-88DD-44DE-9DD5-882D6DE57189}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
41 | {0FB5C73E-88DD-44DE-9DD5-882D6DE57189}.Debug|Any CPU.Build.0 = Debug|Any CPU
42 | {0FB5C73E-88DD-44DE-9DD5-882D6DE57189}.Debug|Any CPU.Deploy.0 = Debug|Any CPU
43 | {0FB5C73E-88DD-44DE-9DD5-882D6DE57189}.Release|Any CPU.ActiveCfg = Release|Any CPU
44 | {0FB5C73E-88DD-44DE-9DD5-882D6DE57189}.Release|Any CPU.Build.0 = Release|Any CPU
45 | {0FB5C73E-88DD-44DE-9DD5-882D6DE57189}.Release|Any CPU.Deploy.0 = Release|Any CPU
46 | {871A0F9B-294C-4DAA-8FE1-7B2E37D14DFA}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
47 | {871A0F9B-294C-4DAA-8FE1-7B2E37D14DFA}.Debug|Any CPU.Build.0 = Debug|Any CPU
48 | {871A0F9B-294C-4DAA-8FE1-7B2E37D14DFA}.Release|Any CPU.ActiveCfg = Release|Any CPU
49 | {871A0F9B-294C-4DAA-8FE1-7B2E37D14DFA}.Release|Any CPU.Build.0 = Release|Any CPU
50 | EndGlobalSection
51 | GlobalSection(SolutionProperties) = preSolution
52 | HideSolutionNode = FALSE
53 | EndGlobalSection
54 | GlobalSection(ExtensibilityGlobals) = postSolution
55 | SolutionGuid = {503DB0F7-38A4-4604-B78B-4C3ABA9C857D}
56 | EndGlobalSection
57 | EndGlobal
58 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool/ApigeeToApimMigrationTool.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Exe
5 | net7.0
6 | enable
7 | enable
8 |
9 | false
10 | true
11 |
12 |
13 | win10-x64;linux-x64
14 |
15 | AnyCPU
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
32 |
33 |
34 |
35 |
36 |
37 | True
38 | True
39 | Resources.resx
40 |
41 |
42 |
43 |
44 |
45 | ResXFileCodeGenerator
46 | Resources.Designer.cs
47 |
48 |
49 |
50 |
51 |
52 | Always
53 |
54 |
55 | Always
56 |
57 |
58 | Always
59 |
60 |
61 | Always
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool/Properties/launchSettings.json:
--------------------------------------------------------------------------------
1 | {
2 | "profiles": {
3 | "ApigeeToApimMigrationTool": {
4 | "commandName": "Project",
5 | "commandLineArgs": "--configFile apigeeToApimConfig.json"
6 | }
7 | }
8 | }
--------------------------------------------------------------------------------
/ApigeeToApimMigrationTool/apigeeToApimConfig.SAMPLE.json:
--------------------------------------------------------------------------------
1 | {
2 | "ConnectionStrings": {
3 | "DataConnection": ""
4 | },
5 | "Apigee": {
6 | "OrganizationName": "my apigee org",
7 | "AuthenticationBaseUrl": "https://yourcompany.login.apigee.com",
8 | "ManagementBaseUrl": "https://api.enterprise.apigee.com",
9 | "Passcode": "my passcode",
10 | "Username": "my username",
11 | "Password": "my password",
12 | "ProxyOrProduct": "Product",
13 | "ProxyOrProductName": "MyProductName",
14 | "EnvironmentName": "my environment",
15 | "ConfigDir": "C:\\apigee\\files\\MyFiles",
16 | "UseTestService": false
17 | },
18 | "Entra": {
19 | "AppId": "my app ID",
20 | "Password": "my app secret",
21 | "TenantId": "my tenant ID",
22 | "SubscriptionId": "my subscription ID"
23 | },
24 | "Apim": {
25 | "Url": "https://my-apim.azure-api.net",
26 | "Name": "my-apim-name",
27 | "ResourceGroup": "My_Apim_Resource_Group",
28 | "OAuthConfigName": "my-apim-oauth-config-name",
29 | "OAuthBackendAppId": "my-apim-oauth-backend-app-id",
30 | "OAuthTenantId": "my-apim-oauth-tenant-id"
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/ApigeeToAzureApimMigrationTool.Core.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Config/ApigeeConfiguration.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ApigeeToApimMigrationTool.Core.Config
8 | {
9 | public class ApigeeConfiguration
10 | {
11 | public string? OrganizationName { get; set; }
12 | public string? AuthenticationBaseUrl { get; set; }
13 | public string? ManagementBaseUrl { get; set; }
14 | public string? Passcode { get; set; }
15 | public string? Username { get; set; }
16 | public string? Password { get; set; }
17 | public string? ProxyOrProduct { get; set; }
18 | public string? ProxyOrProductName { get; set; }
19 | public string? EnvironmentName { get; set; }
20 | public string? ConfigDir { get; set; }
21 | public bool UseTestService { get; set; }
22 | public bool UseApigeeDisplayName { get; set; }
23 | }
24 | }
25 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Config/ApigeeConfigurationBinder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.CommandLine;
4 | using System.CommandLine.Binding;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace ApigeeToApimMigrationTool.Core.Config
10 | {
11 | public class ApigeeConfigurationBinder : BinderBase
12 | {
13 | private readonly Option _organizationNameOption;
14 | private readonly Option _authenticationBaseUrlOption;
15 | private readonly Option _managementBaseUrlOption;
16 | private readonly Option _passcodeOption;
17 | private readonly Option _usernameOption;
18 | private readonly Option _passwordOption;
19 | private readonly Option _proxyOrProductOption;
20 | private readonly Option _proxyOrProductNameOption;
21 | private readonly Option _environmentNameOption;
22 | private readonly Option _configDirOption;
23 | private readonly Option _useApigeeDisplayName;
24 |
25 | public ApigeeConfigurationBinder(
26 | Option organizationNameOption,
27 | Option authenticationBaseUrlOption,
28 | Option managementBaseUrlOption,
29 | Option passcodeOption,
30 | Option usernameOption,
31 | Option passwordOption,
32 | Option proxyOrProductOption,
33 | Option proxyOrProductNameOption,
34 | Option environmentNameOption,
35 | Option configDirOption,
36 | Option useApigeeDisplayName)
37 | {
38 | _organizationNameOption = organizationNameOption;
39 | _authenticationBaseUrlOption = authenticationBaseUrlOption;
40 | _managementBaseUrlOption = managementBaseUrlOption;
41 | _passcodeOption = passcodeOption;
42 | _usernameOption = usernameOption;
43 | _passwordOption = passwordOption;
44 | _proxyOrProductOption = proxyOrProductOption;
45 | _proxyOrProductNameOption = proxyOrProductNameOption;
46 | _environmentNameOption = environmentNameOption;
47 | _configDirOption = configDirOption;
48 | _useApigeeDisplayName = useApigeeDisplayName;
49 | }
50 |
51 | protected override ApigeeConfiguration GetBoundValue(BindingContext bindingContext) =>
52 | new ApigeeConfiguration
53 | {
54 | OrganizationName = bindingContext.ParseResult.GetValueForOption(_organizationNameOption),
55 | AuthenticationBaseUrl = bindingContext.ParseResult.GetValueForOption(_authenticationBaseUrlOption),
56 | ManagementBaseUrl = bindingContext.ParseResult.GetValueForOption(_managementBaseUrlOption),
57 | Passcode = bindingContext.ParseResult.GetValueForOption(_passcodeOption),
58 | Username = bindingContext.ParseResult.GetValueForOption(_usernameOption),
59 | Password = bindingContext.ParseResult.GetValueForOption(_passwordOption),
60 | ProxyOrProduct = bindingContext.ParseResult.GetValueForOption(_proxyOrProductOption),
61 | ProxyOrProductName = bindingContext.ParseResult.GetValueForOption(_proxyOrProductNameOption),
62 | EnvironmentName = bindingContext.ParseResult.GetValueForOption(_environmentNameOption),
63 | ConfigDir = bindingContext.ParseResult.GetValueForOption(_configDirOption),
64 | UseApigeeDisplayName = bindingContext.ParseResult.GetValueForOption(_useApigeeDisplayName)
65 | };
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Config/ApimConfiguration.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ApigeeToApimMigrationTool.Core.Config
8 | {
9 | public class ApimConfiguration
10 | {
11 | public string? Url { get; set; }
12 | public string? Name { get; set; }
13 | public string? ResourceGroup { get; set; }
14 | public string? OAuthConfigName { get; set; }
15 | public string? OAuthBackendAppId { get; set; }
16 | public string? OAuthTenantId { get; set; }
17 | public string? OAuthAudiences { get; set; }
18 | public string? OAuthIssuers { get; set; }
19 | public string? OAuthScopeClaimName { get; set; }
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Config/ApimConfigurationBinder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.CommandLine;
4 | using System.CommandLine.Binding;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace ApigeeToApimMigrationTool.Core.Config
10 | {
11 | public class ApimConfigurationBinder : BinderBase
12 | {
13 | private readonly Option _urlOption;
14 | private readonly Option _nameOption;
15 | private readonly Option _resourceGroupOption;
16 | private readonly Option _oAuthConfigNameOption;
17 | private readonly Option _oAuthBackendAppIdOption;
18 | private readonly Option _oAuthTenantIdOption;
19 | private readonly Option _oAuthAudienceOption;
20 | private readonly Option _oAuthIssuersOptionn;
21 | private readonly Option _oAuthScopeClaimNameOptionn;
22 |
23 | public ApimConfigurationBinder(
24 | Option urlOption,
25 | Option nameOption,
26 | Option resourceGroupOption,
27 | Option oAuthConfigNameOption,
28 | Option oAuthBackendAppIdOption,
29 | Option oAuthTenantIdOption,
30 | Option oAuthAudienceOption,
31 | Option oAuthIssuersOptionn,
32 | Option oAuthScopeClaimNameOptionn)
33 | {
34 | _nameOption = nameOption;
35 | _resourceGroupOption = resourceGroupOption;
36 | _oAuthConfigNameOption = oAuthConfigNameOption;
37 | _oAuthBackendAppIdOption = oAuthBackendAppIdOption;
38 | _oAuthTenantIdOption = oAuthTenantIdOption;
39 | _oAuthAudienceOption = oAuthAudienceOption;
40 | _oAuthIssuersOptionn = oAuthIssuersOptionn;
41 | _oAuthScopeClaimNameOptionn = oAuthScopeClaimNameOptionn;
42 | _urlOption = urlOption;
43 | }
44 |
45 | protected override ApimConfiguration GetBoundValue(BindingContext bindingContext) => new ApimConfiguration
46 | {
47 | Url = bindingContext.ParseResult.GetValueForOption(_urlOption),
48 | Name = bindingContext.ParseResult.GetValueForOption(_nameOption),
49 | ResourceGroup = bindingContext.ParseResult.GetValueForOption(_resourceGroupOption),
50 | OAuthConfigName = bindingContext.ParseResult.GetValueForOption(_oAuthConfigNameOption),
51 | OAuthBackendAppId = bindingContext.ParseResult.GetValueForOption(_oAuthBackendAppIdOption),
52 | OAuthTenantId = bindingContext.ParseResult.GetValueForOption(_oAuthTenantIdOption),
53 | OAuthAudiences = bindingContext.ParseResult.GetValueForOption(_oAuthAudienceOption),
54 | OAuthIssuers = bindingContext.ParseResult.GetValueForOption(_oAuthIssuersOptionn),
55 | OAuthScopeClaimName = bindingContext.ParseResult.GetValueForOption(_oAuthScopeClaimNameOptionn)
56 | };
57 |
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Config/EntraConfiguration.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ApigeeToApimMigrationTool.Core.Config
8 | {
9 | public class EntraConfiguration
10 | {
11 | public string? AppId { get; set; }
12 | public string? Password { get; set; }
13 | public string? TenantId { get; set; }
14 | public string? SubscriptionId { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Config/EntraConfigurationBinder.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.CommandLine;
4 | using System.CommandLine.Binding;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace ApigeeToApimMigrationTool.Core.Config
10 | {
11 | public class EntraConfigurationBinder : BinderBase
12 | {
13 | private readonly Option _appIdOption;
14 | private readonly Option _passwordOption;
15 | private readonly Option _tenantIdOption;
16 | private readonly Option _subscriptionIdOption;
17 |
18 | public EntraConfigurationBinder(
19 | Option appIdOption,
20 | Option passwordOption,
21 | Option tenantIdOption,
22 | Option subscriptionIdOption)
23 | {
24 | _appIdOption = appIdOption;
25 | _passwordOption = passwordOption;
26 | _tenantIdOption = tenantIdOption;
27 | _subscriptionIdOption = subscriptionIdOption;
28 | }
29 |
30 | protected override EntraConfiguration GetBoundValue(BindingContext bindingContext) =>
31 | new EntraConfiguration
32 | {
33 | AppId = bindingContext.ParseResult.GetValueForOption(_appIdOption),
34 | Password = bindingContext.ParseResult.GetValueForOption(_passwordOption),
35 | TenantId = bindingContext.ParseResult.GetValueForOption(_tenantIdOption),
36 | SubscriptionId = bindingContext.ParseResult.GetValueForOption(_subscriptionIdOption)
37 | };
38 | }
39 | }
40 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Dto/ApiProductMetaData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ApigeeToAzureApimMigrationTool.Core.dto
8 | {
9 | public class ApiProductMetaData
10 | {
11 | public string DisplayName { get; set; }
12 | public string Description { get; set; }
13 | public string Name { get; set; }
14 | public IList Proxies { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Dto/ApiProxyEndpointMetadata.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ApigeeToAzureApimMigrationTool.Core.dto
8 | {
9 | public class ApiProxyEndpointMetadata
10 | {
11 | public ApiProxyEndpointConnection Connection { get; set; }
12 | }
13 |
14 | public class ApiProxyEndpointConnection
15 | {
16 | public string BasePath { get; set; }
17 | public string ConnectionType { get; set; }
18 | public string[] VirtualHost { get; set; }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Dto/ApiProxyMetaData.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ApigeeToAzureApimMigrationTool.Core.Dto
8 | {
9 | public class ApiProxyMetaData
10 | {
11 | public long createdAt { get; set; }
12 | public string createdBy { get; set; }
13 | public long lastModifiedAt { get; set; }
14 | public string lastModifiedBy { get; set; }
15 | public string subType { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Dto/ApiProxyRevisionMetadata.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ApigeeToAzureApimMigrationTool.Core.Dto
8 | {
9 | public class ApiProxyRevisionMetadata
10 | {
11 | public int Id { get; set; }
12 | public string[] BasePaths { get; set; }
13 | public string Name { get; set; }
14 | public int Revision { get; set; }
15 | public string Description { get; set; }
16 | public string[] Policies { get; set; }
17 | public string[] ProxyEndpoints { get; set; }
18 | public Dictionary ProxyEndpointPaths { get; set; }
19 |
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Dto/ApigeeEntityModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Security.Cryptography.X509Certificates;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace ApigeeToAzureApimMigrationTool.Core.Dto
9 | {
10 | public class ApigeeEntityModel
11 | {
12 | public string name { get; set; }
13 | public string[] revision { get; set; }
14 | public ApiProxyMetaData metaData { get; set; }
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Dto/ApigeeTargetServerModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ApigeeToAzureApimMigrationTool.Core.Dto
8 | {
9 | public class ApigeeTargetServerModel
10 | {
11 | public string Host { get; set; }
12 | public bool IsEnabled { get; set; }
13 | public string Name { get; set; }
14 | public int Port { get; set; }
15 | public ApigeeTargetServerSSLInfo SSLInfo { get; set; }
16 | }
17 |
18 | public class ApigeeTargetServerSSLInfo
19 | {
20 | public ICollection Ciphers { get; set; }
21 | public bool ClientAuthEnabled { get; set; }
22 | public bool Enabled { get; set; }
23 | public bool IgnoreValidationError { get; set; }
24 | public ICollection Protocols { get; set; }
25 | public string TrustStore { get; set; }
26 | }
27 | }
28 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Dto/ApimConfig.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ApigeeToAzureApimMigrationTool.Core.dto
8 | {
9 | public class ApimConfig
10 | {
11 | public string ApimUrl { get; set; }
12 | public string ApimName { get; set; }
13 | public string ApimResourceGroupName { get; set; }
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Dto/AuthToken.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ApigeeToAzureApimMigrationTool.Core.Dto
8 | {
9 | public class AuthToken
10 | {
11 | public string access_token { get; set; }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Dto/AzureCredentials.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ApigeeToAzureApimMigrationTool.Core.Dto
8 | {
9 | public class AzureCredentials
10 | {
11 | public Guid AppId { get; set; }
12 | public string DisplayName { get; set; }
13 | public string Password { get; set; }
14 | public Guid Tenant { get; set; }
15 | public string SubscriptionId { get; set; }
16 | }
17 | }
18 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Dto/KeyValueMapModel.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ApigeeToAzureApimMigrationTool.Core.dto
8 | {
9 | public class KeyValueMapModel
10 | {
11 | public bool Encrypted { get; set; }
12 | public string Name { get; set; }
13 | public ICollection Entry { get; set; }
14 | }
15 |
16 | public class KeyValueMapItemModel
17 | {
18 | public string Name { get; set; }
19 | public string Value { get; set; }
20 | }
21 | }
22 |
23 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Enum/AssignMessagePolicyOperations.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.ComponentModel;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace ApigeeToAzureApimMigrationTool.Core.Enum
9 | {
10 | public enum AssignMessagePolicyOperations
11 | {
12 | Add,
13 | Remove,
14 | Set
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Enum/PolicyDirection.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ApigeeToAzureApimMigrationTool.Core.Enum
8 | {
9 | public enum PolicyDirection
10 | {
11 | Inbound,
12 | Outbound
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Interface/IApigeeManagementApiService.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core.dto;
2 | using ApigeeToAzureApimMigrationTool.Core.Dto;
3 |
4 | namespace ApigeeToAzureApimMigrationTool.Core
5 | {
6 | public interface IApigeeManagementApiService
7 | {
8 | string AuthenticationToken { get; set; }
9 | string Username { get; set; }
10 | string Password { get; set; }
11 | string? Environment { get; }
12 | string ProxyName { get; }
13 | Task DownloadApiProxyBundle(string basePath, string proxyName, int revision);
14 | Task GetApiProxyByName(string proxyName);
15 | Task DownloadSharedFlowBundle(string basePath, string sharedFlowName, int revision);
16 | Task GetSharedFlowByName(string sharedFlowName);
17 | Task PopulateProxyReferenceDatabase();
18 | Task GetApiProductByName(string productName);
19 | Task GetTargetServerByName(string targetServerName, string environment);
20 | Task GetKeyValueMapByName(string proxyName, string environment, string mapIdentifier);
21 | }
22 | }
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Interface/IApigeeXmlLoader.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 | using System.Xml.Linq;
7 |
8 | namespace ApigeeToAzureApimMigrationTool.Core.Interface
9 | {
10 | public interface IApigeeXmlLoader
11 | {
12 | public XDocument LoadProxyXml(string proxyName);
13 |
14 | public XDocument LoadTargetXml(string proxyName, string targetEndpointName);
15 |
16 | public XDocument LoadProxyEndpointXml(string proxyName, string proxyEndpointName);
17 | public XDocument LoadPolicyXml(string proxyName, string policyName);
18 | public XDocument LoadSharedFlowBundleXml(string sharedFlowName);
19 | public XDocument LoadSharedFlowXml(string sharedFlowName, string sharedFlowFileName);
20 | public XDocument LoadSharedFlowPolicyXml(string sharedFlowName, string policyName);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Interface/IApimPolicyTransformer.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToApimMigrationTool.Core.Config;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Xml.Linq;
8 |
9 | namespace ApigeeToAzureApimMigrationTool.Core.Interface
10 | {
11 | public interface IApimPolicyTransformer
12 | {
13 | Task TransformPoliciesInCollection(IEnumerable? elements, XElement azureApimPolicySection, Func xmlLoader,
14 | string apimName, string proxyName, ApigeeConfiguration apigeeConfiguration, ApimConfiguration apimConfig);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Interface/IApimProvider.cs:
--------------------------------------------------------------------------------
1 | using Azure.ResourceManager.ApiManagement;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Xml.Linq;
8 |
9 | namespace ApigeeToAzureApimMigrationTool.Core.Interface
10 | {
11 | public interface IApimProvider
12 | {
13 | string ApimName { get; }
14 | string ApimUrl { get; }
15 | Task CreateApi(string apiName, string apiDisplayName, string apiDescription, string apimName,
16 | string revision, string apiPath, string backendUrl, string? oauthConfigurationName);
17 | Task CreateProduct(string name, string displayName, string description, string apimName);
18 | Task CreatePolicyFragment(string policyFragmentName, string apimName, string policyFragmentXml, string policyFragmentDescription);
19 | Task CreatePolicy(XDocument policyXml);
20 | Task CreateOrUpdateOperation(string apiName, string description, string httpVerb);
21 | Task CreateOrUpdateOperationPolicy(XDocument operationPolicyXml, string operationName, string operationDescription, string httpVerb, string proxyPath);
22 | Task AddApiToProduct(string apiId);
23 | Task AddNamedValue(string apimName, string proxyName, string mapIdentifier, string keyName, bool isSecret, string value, int index = 1);
24 | Task UpdateApiSubscriptionSetting(string apimName, string proxyName, string headerName = "", string queryParameterName = "");
25 |
26 | string RemoveTrailingSpecialCharacters(string input);
27 |
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Interface/IAzureApimService.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToApimMigrationTool.Core.Config;
2 | using Azure.ResourceManager.ApiManagement;
3 |
4 | namespace ApigeeToAzureApimMigrationTool.Core.Interface
5 | {
6 | public interface IAzureApimService
7 | {
8 | Task ImportApi(string apimName, string proxyName, ApimConfiguration apimConfiguration, ApigeeConfiguration apigeeConfiguration, string keyVaultName);
9 |
10 | }
11 | }
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Interface/IBundle.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ApigeeToAzureApimMigrationTool.Core.Interface
8 | {
9 | public interface IBundle
10 | {
11 | Task LoadBundle();
12 | string GetBundlePath();
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Interface/IBundleProvider.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ApigeeToAzureApimMigrationTool.Core.Interface
8 | {
9 | public interface IBundleProvider
10 | {
11 | IBundle GetApiProxyBundle(string proxyOrProductName);
12 | IBundle GetSharedFlowBundle(string sharedFlowName);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Interface/IExpressionTranslator.cs:
--------------------------------------------------------------------------------
1 | using System;
2 | using System.Collections.Generic;
3 | using System.Linq;
4 | using System.Text;
5 | using System.Threading.Tasks;
6 |
7 | namespace ApigeeToAzureApimMigrationTool.Core.Interface
8 | {
9 | public interface IExpressionTranslator
10 | {
11 | bool ContentHasVariablesInIt(string content);
12 | string TranslateSingleItem(string expression, string defaultValue = "");
13 | string TranslateWholeString(string expression);
14 | string TranslateConditionOperator(string expression);
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Interface/IPolicyTransformation.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core.Enum;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Xml.Linq;
8 |
9 | namespace ApigeeToAzureApimMigrationTool.Core.Interface
10 | {
11 | public interface IPolicyTransformation
12 | {
13 | Task> Transform(XElement element, string apigeePolicyName, PolicyDirection policyDirection = PolicyDirection.Inbound);
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Interface/IPolicyTransformationFactory.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToApimMigrationTool.Core.Config;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace ApigeeToAzureApimMigrationTool.Core.Interface
9 | {
10 | public interface IPolicyTransformationFactory
11 | {
12 | IPolicyTransformation GetTransformationForPolicy(string policyName, IList> policyVariables, ApigeeConfiguration apigeeConfiguration, ApimConfiguration apimConfig);
13 | }
14 | }
15 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Core/Interface/IProxyMetaDataDataAccess.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core.Dto;
2 |
3 | namespace ApigeeToApimMigrationTool.Core.Interface
4 | {
5 | public interface IProxyMetaDataDataAccess
6 | {
7 | Task GetProxyRevisionMetaDataByPath(string path);
8 | Task InsertProxyRevisionMetaData(ApiProxyRevisionMetadata metaData);
9 | Task IsProxyMetadataTablePopulted();
10 | }
11 | }
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/ApigeeManagementApiTestFileService.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core;
2 | using ApigeeToAzureApimMigrationTool.Core.dto;
3 | using ApigeeToAzureApimMigrationTool.Core.Dto;
4 | using ApigeeToAzureApimMigrationTool.Core.Interface;
5 | using ApigeeToAzureApimMigrationTool.Service.Bundles;
6 | using Newtonsoft.Json;
7 | using System;
8 | using System.Collections.Generic;
9 | using System.Linq;
10 | using System.Text;
11 | using System.Threading.Tasks;
12 | using System.Xml.Linq;
13 |
14 | namespace ApigeeToAzureApimMigrationTool.Service
15 | {
16 | public class ApigeeManagementApiTestFileService : IApigeeManagementApiService
17 | {
18 | private readonly IBundleProvider _apigeeBundleProvider;
19 | private readonly IApigeeXmlLoader _apigeeXmlLoader;
20 | private readonly string _localConfigPath;
21 | public ApigeeManagementApiTestFileService(IBundleProvider apigeeBundleProvider, IApigeeXmlLoader apigeeXmlLoader, string localConfigPath)
22 | {
23 | _apigeeBundleProvider = apigeeBundleProvider;
24 | _apigeeXmlLoader = apigeeXmlLoader;
25 | _localConfigPath = localConfigPath;
26 | }
27 | public string AuthenticationToken { get; set; }
28 | public string Username { get; set; }
29 | public string Password { get; set; }
30 |
31 | public string? Environment { get; set; }
32 |
33 | public string ProxyName { get; set; }
34 |
35 | public Task GetApiProxyByName(string proxyName)
36 | {
37 | // For testing, do things backwards. Get the metadata from the XML that we've
38 | // already downloaded.
39 | XDocument proxyXml = _apigeeXmlLoader.LoadProxyXml(proxyName);
40 | if (proxyXml.Root == null)
41 | {
42 | throw new Exception($"Could not get xml for proxy {proxyName} from file.");
43 | }
44 |
45 | XElement? apiProxyElement = proxyXml.Root.Element("APIProxy");
46 | if (apiProxyElement == null)
47 | {
48 | throw new Exception($"Could not find APIProxy element in xml for proxy {proxyName}.");
49 | }
50 |
51 | var apiProxyModel = new ApigeeEntityModel();
52 | apiProxyModel.name = apiProxyElement.Attribute("name")?.Value ?? string.Empty;
53 |
54 | string revision = apiProxyElement.Attribute("revision")?.Value ?? string.Empty;
55 | apiProxyModel.revision = new string[] { revision };
56 |
57 | apiProxyModel.metaData = new ApiProxyMetaData();
58 | apiProxyModel.metaData.createdAt = long.Parse(apiProxyElement.Element("CreatedAt")?.Value ?? string.Empty);
59 | apiProxyModel.metaData.createdBy = apiProxyElement.Element("CreatedBy")?.Value ?? string.Empty;
60 | apiProxyModel.metaData.lastModifiedAt = long.Parse(apiProxyElement.Element("LastModifiedAt")?.Value ?? string.Empty);
61 | apiProxyModel.metaData.lastModifiedBy = apiProxyElement.Element("LastModifiedBy")?.Value ?? string.Empty;
62 |
63 | apiProxyModel.metaData.subType = string.Empty;
64 |
65 | return Task.FromResult(apiProxyModel);
66 | }
67 |
68 | public Task GetTargetServerByName(string targetServerName, string environment)
69 | {
70 | var defaultTargetServer = new ApigeeTargetServerModel
71 | {
72 | Host = targetServerName,
73 | IsEnabled = true,
74 | Name = targetServerName,
75 | Port = 8080,
76 | SSLInfo = new ApigeeTargetServerSSLInfo
77 | {
78 | Ciphers = new string[] { "DEFAULT" },
79 | ClientAuthEnabled = false,
80 | Enabled = false,
81 | IgnoreValidationError = false,
82 | Protocols = new string[] { "TLSv1.2" },
83 | TrustStore = "default"
84 | }
85 | };
86 |
87 | return Task.FromResult(defaultTargetServer);
88 | }
89 |
90 | public Task DownloadApiProxyBundle(string basePath, string proxyName, int revision)
91 | {
92 | // Return the path of the already downloaded bundle
93 | var bundle = _apigeeBundleProvider.GetApiProxyBundle(proxyName);
94 | return Task.FromResult(bundle.GetBundlePath());
95 | }
96 |
97 | public Task DownloadSharedFlowBundle(string basePath, string sharedFlowName, int revision)
98 | {
99 | // Return the path of the already downloaded shared flow bundle
100 | var bundle = _apigeeBundleProvider.GetSharedFlowBundle(sharedFlowName);
101 | return Task.FromResult(bundle.GetBundlePath());
102 | }
103 |
104 | public async Task GetApiProductByName(string productName)
105 | {
106 | var defaultApiProductMetaData = new ApiProductMetaData
107 | {
108 | DisplayName = productName,
109 | Description = "Default",
110 | Name = productName,
111 | Proxies = new List(),
112 | };
113 |
114 | // Iterate through the bundle directory and find all the proxies that are in the product
115 | var bundleDirectories = Directory.GetDirectories(_localConfigPath);
116 | foreach (var directory in bundleDirectories)
117 | {
118 | if (Directory.Exists($"{directory}{Path.DirectorySeparatorChar}apiproxy"))
119 | {
120 | defaultApiProductMetaData.Proxies.Add(Path.GetFileName(directory));
121 | }
122 | }
123 | // END TODO
124 |
125 | // Load pre-configured product json file
126 | var apiProductFilePathBuilder = new StringBuilder($"{_localConfigPath}{Path.DirectorySeparatorChar}apiproducts{Path.DirectorySeparatorChar}{productName}.json");
127 |
128 | string apiProductFilePath = apiProductFilePathBuilder.ToString();
129 |
130 | if (!File.Exists(apiProductFilePath))
131 | {
132 | return defaultApiProductMetaData;
133 | }
134 |
135 | string apiProductJson = await File.ReadAllTextAsync(apiProductFilePath);
136 | var apiProductModel = JsonConvert.DeserializeObject(apiProductJson);
137 |
138 | if (apiProductModel == null)
139 | {
140 | return defaultApiProductMetaData;
141 | }
142 |
143 | return apiProductModel;
144 | }
145 |
146 |
147 | public async Task GetKeyValueMapByName(string proxyName, string environment, string mapIdentifier)
148 | {
149 |
150 | // Load pre-configured kvmap json file
151 | var keyValueMapFilePathBuilder = new StringBuilder($"{_localConfigPath}{Path.DirectorySeparatorChar}keyvaluemaps{Path.DirectorySeparatorChar}{mapIdentifier}");
152 | if (!string.IsNullOrEmpty(environment))
153 | {
154 | keyValueMapFilePathBuilder.Append($".{environment}");
155 | }
156 | keyValueMapFilePathBuilder.Append(".json");
157 |
158 | string keyValueMapPath = keyValueMapFilePathBuilder.ToString();
159 |
160 | if (!File.Exists(keyValueMapPath))
161 | {
162 | return null; // Same behavior as real service
163 | }
164 |
165 | string kvmapJson = await File.ReadAllTextAsync(keyValueMapPath);
166 | var kvmapModel = JsonConvert.DeserializeObject(kvmapJson);
167 |
168 | return kvmapModel;
169 | }
170 |
171 | public Task GetSharedFlowByName(string sharedFlowName)
172 | {
173 | // Just like with the API proxy metadata, do things backwards. Get the metadata from the XML that we've
174 | // already downloaded.
175 | // HACK: We're going to assume we've downlaoded the "default.xml" file for the shared flow.
176 | XDocument proxyXml = _apigeeXmlLoader.LoadSharedFlowBundleXml(sharedFlowName);
177 | if (proxyXml.Root == null)
178 | {
179 | throw new Exception($"Could not get xml for shared flow {sharedFlowName} from file.");
180 | }
181 |
182 | XElement? sharedFlowBundleElement = proxyXml.Element("SharedFlowBundle");
183 | if (sharedFlowBundleElement == null)
184 | {
185 | throw new Exception($"Could not find SharedFlowBundle element in xml for shared flow {sharedFlowName}.");
186 | }
187 |
188 | var sharedFlowModel = new ApigeeEntityModel();
189 | sharedFlowModel.name = sharedFlowBundleElement.Attribute("name")?.Value ?? string.Empty;
190 |
191 | string revision = sharedFlowBundleElement.Attribute("revision")?.Value ?? string.Empty;
192 | sharedFlowModel.revision = new string[] { revision };
193 |
194 | sharedFlowModel.metaData = new ApiProxyMetaData();
195 | sharedFlowModel.metaData.createdAt = long.Parse(sharedFlowBundleElement.Element("CreatedAt")?.Value ?? string.Empty);
196 | sharedFlowModel.metaData.createdBy = sharedFlowBundleElement.Element("CreatedBy")?.Value ?? string.Empty;
197 | sharedFlowModel.metaData.lastModifiedAt = long.Parse(sharedFlowBundleElement.Element("LastModifiedAt")?.Value ?? string.Empty);
198 | sharedFlowModel.metaData.lastModifiedBy = sharedFlowBundleElement.Element("LastModifiedBy")?.Value ?? string.Empty;
199 |
200 | sharedFlowModel.metaData.subType = string.Empty;
201 |
202 | return Task.FromResult(sharedFlowModel);
203 | }
204 |
205 |
206 | public Task PopulateProxyReferenceDatabase()
207 | {
208 | throw new NotImplementedException();
209 | }
210 | }
211 | }
212 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/ApigeeToApimPolicyTransformer.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToApimMigrationTool.Core.Config;
2 | using ApigeeToAzureApimMigrationTool.Core.Interface;
3 | using ApigeeToAzureApimMigrationTool.Service.Transformations;
4 | using Azure.ResourceManager.ApiManagement.Models;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Configuration;
8 | using System.Linq;
9 | using System.Net;
10 | using System.Text;
11 | using System.Text.RegularExpressions;
12 | using System.Threading.Tasks;
13 | using System.Web;
14 | using System.Xml.Linq;
15 |
16 | namespace ApigeeToAzureApimMigrationTool.Service
17 | {
18 | public class ApigeeToApimPolicyTransformer : IApimPolicyTransformer
19 | {
20 |
21 | private readonly IPolicyTransformationFactory _policyTransformationFactory;
22 | private readonly List> _policyVariables;
23 | private readonly IApimProvider _apimProvider;
24 | private readonly IExpressionTranslator _expressionTranslator;
25 |
26 | public ApigeeToApimPolicyTransformer(IPolicyTransformationFactory policyTransformationFactory, IApimProvider apimProvider, IExpressionTranslator expressionTranslator)
27 | {
28 | _policyTransformationFactory = policyTransformationFactory;
29 | _policyVariables = new List>();
30 | _apimProvider = apimProvider;
31 | _expressionTranslator = expressionTranslator;
32 | }
33 | public async Task TransformPoliciesInCollection(IEnumerable? elements, XElement azureApimPolicySection, Func xmlLoader,
34 | string apimName, string proxyName, ApigeeConfiguration apigeeConfiguration, ApimConfiguration apimConfig)
35 | {
36 | if (elements == null)
37 | {
38 | return;
39 | }
40 |
41 | foreach (var element in elements)
42 | {
43 | if (element == null)
44 | {
45 | continue;
46 | }
47 |
48 | string? policyName = element.Element("Name")?.Value;
49 |
50 | if (policyName == null)
51 | {
52 | throw new Exception($"Cannot find Name element in policy xml: {element}");
53 | }
54 |
55 | XElement? conditionElement = element.Element("Condition");
56 | string? condition = conditionElement?.Value;
57 |
58 | if (condition == null)
59 | {
60 | condition = string.Empty;
61 | }
62 |
63 | var policyXml = xmlLoader(proxyName, policyName);
64 |
65 | var rootElement = policyXml.Root;
66 | if (rootElement == null)
67 | {
68 | throw new Exception($"Cannot find root element in policy xml: {policyXml}");
69 | }
70 |
71 | await TransformPolicy(proxyName, rootElement, rootElement.Name.ToString(), azureApimPolicySection, apimName, condition, policyName, apigeeConfiguration, apimConfig);
72 | }
73 |
74 | }
75 |
76 | private async Task TransformPolicy(string apiProxyName, XElement element, string apigeePolicyName, XElement apimPolicyElement, string apimName, string condition, string apigeePolicyDisplayName,
77 | ApigeeConfiguration apigeeConfiguration, ApimConfiguration apimConfig)
78 | {
79 | IPolicyTransformation? policyTransformation = default;
80 | if (apigeePolicyName.Equals("VerifyAPIKey"))
81 | {
82 | string headerValue = "";
83 | string queryParameterValue = "";
84 | var source = element.Element("APIKey").Attribute("ref").Value;
85 | if (source.StartsWith("request.header"))
86 | headerValue = source.Replace("request.header.", "");
87 | else if (source.StartsWith("request.queryparam"))
88 | queryParameterValue = source.Replace("request.queryparam.", "");
89 |
90 | await _apimProvider.UpdateApiSubscriptionSetting(apimConfig.Name, apiProxyName, headerValue, queryParameterValue);
91 | }
92 | else
93 | {
94 | policyTransformation = _policyTransformationFactory.GetTransformationForPolicy(apigeePolicyName, _policyVariables, apigeeConfiguration, apimConfig);
95 | var apimPolicies = await policyTransformation.Transform(element, apigeePolicyDisplayName);
96 | foreach (var apimPolicy in apimPolicies)
97 | {
98 | var policyWithCondition = ApplyConditionToPolicy(condition, apimPolicy);
99 | apimPolicyElement.Add(policyWithCondition);
100 | }
101 | }
102 |
103 | // Special handling for Shared Flows, for which additional policies need to be downloaded from Apigee
104 | // and then processed by this transformer entirely separately
105 | var flowCalloutTransformation = policyTransformation as FlowCalloutTransformation;
106 | if (flowCalloutTransformation != null)
107 | {
108 | await flowCalloutTransformation.DonwloadAndTransformSharedFlow(this);
109 | }
110 | }
111 |
112 | private XElement ApplyConditionToPolicy(string condition, XElement policy)
113 | {
114 | if (!string.IsNullOrEmpty(condition))
115 | {
116 |
117 | condition = _expressionTranslator.TranslateWholeString(condition);
118 |
119 | string requestHeaderPattern = "request\\.header\\.([-\\w]+)";
120 | foreach (Match match in Regex.Matches(condition, requestHeaderPattern))
121 | {
122 | if (match.Success && match.Groups.Count > 0)
123 | {
124 | var HeaderName = match.Groups[1].Value;
125 | string completeExpression = $"request.header.{HeaderName}";
126 | condition = condition.Replace(completeExpression, $"context.Request.Headers.GetValueOrDefault(\"{HeaderName}\", \"\")");
127 | }
128 | }
129 |
130 | string cacheLookupPattern = @"lookupcache.(.*?).cachehit";
131 | foreach (Match match in Regex.Matches(condition, cacheLookupPattern))
132 | {
133 | if (match.Success && match.Groups.Count > 0)
134 | {
135 | var policyName = match.Groups[1].Value;
136 | string completeExpression = $"lookupcache.{policyName}.cachehit";
137 | string variableName = _policyVariables.FirstOrDefault(x => x.Key == policyName).Value;
138 | condition = condition.Replace(completeExpression, $"context.Variables.ContainsKey(\"{variableName}\")");
139 | }
140 | }
141 |
142 | string jwtValidPattern = @"jwt.(.*?).valid";
143 | foreach (Match match in Regex.Matches(condition, jwtValidPattern))
144 | {
145 | if (match.Success && match.Groups.Count > 0)
146 | {
147 | var policyName = match.Groups[1].Value;
148 | string completeExpression = $"jwt.{policyName}.valid";
149 | string variableName = _policyVariables.FirstOrDefault(x => x.Key == policyName).Value;
150 | condition = condition.Replace(completeExpression, $"context.Variables.ContainsKey(\"{variableName}\")");
151 | }
152 | }
153 |
154 | string variableEqualsValue = "(\\S+)\\s(=|==|!=|=\\\\|)\\s(\\S+)";
155 | foreach (Match match in Regex.Matches(condition, variableEqualsValue))
156 | {
157 | if (match.Success && match.Groups.Count > 0 && !match.Groups[0].Value.Contains("context."))
158 | {
159 | var variableName = match.Groups[1].Value;
160 | var conditionOperator = match.Groups[2].Value;
161 | var variableValue = match.Groups[3].Value;
162 | if (!variableName.Contains("context") && !string.IsNullOrEmpty(variableName))
163 | {
164 | string valueToReplace = match.Groups[0].Value;
165 | valueToReplace = valueToReplace.Replace("(", "").Replace(")", "");
166 | condition = condition.Replace(valueToReplace, $"context.Variables.GetValueOrDefault<{GetDataTypeFromStringValue(variableValue)}>(\"{variableName.Replace("(", "").Replace(")", "")}\") {conditionOperator} {variableValue.Replace("(", "").Replace(")", "")}");
167 | }
168 | }
169 | }
170 |
171 |
172 |
173 | condition = $"@({condition})";
174 | var conditionelement = new XElement("choose", new XElement("when", ""));
175 | conditionelement.Element("when").SetAttributeValue("condition", HttpUtility.HtmlDecode(condition));
176 | conditionelement.Element("when").Add(policy);
177 | return conditionelement;
178 | }
179 | else
180 | return policy;
181 | }
182 |
183 | private string GetDataTypeFromStringValue(string str)
184 | {
185 | bool boolValue;
186 | Int32 intValue;
187 | Int64 bigintValue;
188 | double doubleValue;
189 | DateTime dateValue;
190 |
191 | if (bool.TryParse(str, out boolValue))
192 | return "bool";
193 | else if (Int32.TryParse(str, out intValue))
194 | return "int";
195 | else if (Int64.TryParse(str, out bigintValue))
196 | return "Int64";
197 | else if (double.TryParse(str, out doubleValue))
198 | return "double";
199 | else if (DateTime.TryParse(str, out dateValue))
200 | return "DateTime";
201 | else return "string";
202 |
203 | }
204 |
205 |
206 | }
207 | }
208 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/ApigeeToAzureApimMigrationTool.Service.csproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | net7.0
5 | enable
6 | enable
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/ApigeeXmlFileLoader.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core.Interface;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 | using System.Xml.Linq;
8 |
9 | namespace ApigeeToAzureApimMigrationTool.Service
10 | {
11 | public class ApigeeXmlFileLoader : IApigeeXmlLoader
12 | {
13 | private readonly IBundleProvider _bundleProvider;
14 | public ApigeeXmlFileLoader(IBundleProvider bundle)
15 | {
16 | _bundleProvider = bundle;
17 | }
18 | public XDocument LoadProxyXml(string proxyName)
19 | {
20 | var bundle = _bundleProvider.GetApiProxyBundle(proxyName);
21 | return XDocument.Load(Path.Combine(bundle.GetBundlePath(), $"{proxyName}.xml"));
22 | }
23 |
24 | public XDocument LoadTargetXml(string proxyName, string targetEndpointName)
25 | {
26 | var bundle = _bundleProvider.GetApiProxyBundle(proxyName);
27 | return XDocument.Load(Path.Combine(bundle.GetBundlePath(), "targets", $"{targetEndpointName}.xml"));
28 | }
29 |
30 | public XDocument LoadProxyEndpointXml(string proxyName, string proxyEndpointName)
31 | {
32 | var bundle = _bundleProvider.GetApiProxyBundle(proxyName);
33 | return XDocument.Load(Path.Combine(bundle.GetBundlePath(), "proxies", $"{proxyEndpointName}.xml"));
34 | }
35 |
36 | public XDocument LoadPolicyXml(string proxyName, string policyName)
37 | {
38 | var bundle = _bundleProvider.GetApiProxyBundle(proxyName);
39 | return XDocument.Load(Path.Combine(bundle.GetBundlePath(), "policies", $"{policyName}.xml"));
40 | }
41 |
42 | public XDocument LoadSharedFlowBundleXml(string sharedFlowName)
43 | {
44 | var bundle = _bundleProvider.GetSharedFlowBundle(sharedFlowName);
45 | return XDocument.Load(Path.Combine(bundle.GetBundlePath(), $"{sharedFlowName}.xml"));
46 | }
47 |
48 | public XDocument LoadSharedFlowXml(string sharedFlowName, string sharedFlowFileName)
49 | {
50 | var bundle = _bundleProvider.GetSharedFlowBundle(sharedFlowName);
51 | return XDocument.Load(Path.Combine(bundle.GetBundlePath(), "sharedflows", $"{sharedFlowFileName}.xml"));
52 | }
53 |
54 | public XDocument LoadSharedFlowPolicyXml(string sharedFlowName, string policyName)
55 | {
56 | var bundle = _bundleProvider.GetSharedFlowBundle(sharedFlowName);
57 | return XDocument.Load(Path.Combine(bundle.GetBundlePath(), "policies", $"{policyName}.xml"));
58 | }
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Bundles/ApigeeFileApiProxyBundle.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core;
2 | using ApigeeToAzureApimMigrationTool.Core.Interface;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace ApigeeToAzureApimMigrationTool.Service.Bundles
10 | {
11 | public class ApigeeFileApiProxyBundle : IBundle
12 | {
13 | private string _bundleBasePath;
14 | private string _proxyOrProductName;
15 |
16 | public ApigeeFileApiProxyBundle(string bundleBasePath, string proxyOrProductName)
17 | {
18 | _bundleBasePath = bundleBasePath;
19 | _proxyOrProductName = proxyOrProductName;
20 | }
21 |
22 | public string GetBundlePath()
23 | {
24 | if (string.IsNullOrEmpty(_proxyOrProductName))
25 | {
26 | throw new Exception("API Proxy bundle not loaded. Please load the bundle first");
27 | }
28 |
29 | return Path.Combine(_bundleBasePath, _proxyOrProductName, "apiproxy");
30 | }
31 |
32 | public Task LoadBundle()
33 | {
34 | // Nothing to return, the bundle is already in the filesystem
35 | return Task.CompletedTask;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Bundles/ApigeeFileBundleProvider.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core.Interface;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Text;
6 | using System.Threading.Tasks;
7 |
8 | namespace ApigeeToAzureApimMigrationTool.Service.Bundles
9 | {
10 | public class ApigeeFileBundleProvider : IBundleProvider
11 | {
12 | private readonly IDictionary _apiProxyBundles;
13 | private readonly IDictionary _sharedFlowBundles;
14 |
15 | private readonly string _bundleBasePath;
16 |
17 | public ApigeeFileBundleProvider(string bundleBasePath)
18 | {
19 | _apiProxyBundles = new Dictionary();
20 | _sharedFlowBundles = new Dictionary();
21 |
22 | _bundleBasePath = bundleBasePath;
23 | }
24 |
25 | public IBundle GetApiProxyBundle(string proxyOrProductName)
26 | {
27 | if (!_apiProxyBundles.ContainsKey(proxyOrProductName))
28 | {
29 | _apiProxyBundles.Add(proxyOrProductName, new ApigeeFileApiProxyBundle(_bundleBasePath, proxyOrProductName));
30 | }
31 | return _apiProxyBundles[proxyOrProductName];
32 | }
33 |
34 | public IBundle GetSharedFlowBundle(string sharedFlowName)
35 | {
36 | if (!_sharedFlowBundles.ContainsKey(sharedFlowName))
37 | {
38 | _sharedFlowBundles.Add(sharedFlowName, new ApigeeFileSharedFlowBundle(_bundleBasePath, sharedFlowName));
39 | }
40 | return _sharedFlowBundles[sharedFlowName];
41 | }
42 | }
43 | }
44 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Bundles/ApigeeFileSharedFlowBundle.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core;
2 | using ApigeeToAzureApimMigrationTool.Core.Interface;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace ApigeeToAzureApimMigrationTool.Service
10 | {
11 | public class ApigeeFileSharedFlowBundle : IBundle
12 | {
13 | private string _bundleBasePath;
14 | private string _sharedFlowName;
15 |
16 | public ApigeeFileSharedFlowBundle(string bundleBasePath, string sharedFlowName)
17 | {
18 | _bundleBasePath = bundleBasePath;
19 | _sharedFlowName = sharedFlowName;
20 | }
21 |
22 | public string GetBundlePath()
23 | {
24 | if (string.IsNullOrEmpty(_sharedFlowName))
25 | {
26 | throw new Exception("Shared flow bundle not loaded. Please load the bundle first");
27 | }
28 |
29 | return Path.Combine(_bundleBasePath, _sharedFlowName, "sharedflowbundle");
30 | }
31 |
32 | public Task LoadBundle()
33 | {
34 | // Nothing to return, the bundle is already in the filesystem
35 | return Task.CompletedTask;
36 | }
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Bundles/ApigeeOnlineApiProxyBundle.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core;
2 | using ApigeeToAzureApimMigrationTool.Core.Interface;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace ApigeeToAzureApimMigrationTool.Service.Bundles
10 | {
11 | public class ApigeeOnlineApiProxyBundle : IBundle
12 | {
13 | private readonly IApigeeManagementApiService _apigeeManagementApiService;
14 | private readonly string _basePath;
15 | private readonly string _proxyOrProductName;
16 | private string? _bundlePath;
17 |
18 | public ApigeeOnlineApiProxyBundle(string basePath, string proxyOrProductName, IApigeeManagementApiService apigeeManagementApiService)
19 | {
20 | _basePath = basePath;
21 | _proxyOrProductName = proxyOrProductName;
22 | _apigeeManagementApiService = apigeeManagementApiService;
23 | }
24 |
25 | public async Task LoadBundle()
26 | {
27 | //get api metadata
28 | var apiProxyMetadata = await _apigeeManagementApiService.GetApiProxyByName(_proxyOrProductName);
29 | //get the latest revision
30 | int maxRevision = apiProxyMetadata.revision.Select(x => int.Parse(x)).Max();
31 | //download api proxy bundle
32 | _bundlePath = await _apigeeManagementApiService.DownloadApiProxyBundle(_basePath, _proxyOrProductName, maxRevision);
33 | }
34 | public string GetBundlePath()
35 | {
36 | if (string.IsNullOrEmpty(_bundlePath))
37 | {
38 | throw new Exception("Bundle not loaded. Please load the bundle first");
39 | }
40 |
41 | return Path.Combine(_basePath, _proxyOrProductName, "apiproxy");
42 |
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Bundles/ApigeeOnlineBundleProvider.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core;
2 | using ApigeeToAzureApimMigrationTool.Core.Interface;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace ApigeeToAzureApimMigrationTool.Service.Bundles
10 | {
11 | public class ApigeeOnlineBundleProvider : IBundleProvider
12 | {
13 | private readonly IApigeeManagementApiService _apigeeManagementApiService;
14 | private readonly IDictionary _apiProxyBundles;
15 | private readonly IDictionary _sharedFlowBundles;
16 |
17 | private readonly string _bundleBasePath;
18 |
19 | public ApigeeOnlineBundleProvider(string bundleBasePath, IApigeeManagementApiService apigeeManagementApiService)
20 | {
21 | _apigeeManagementApiService = apigeeManagementApiService;
22 | _apiProxyBundles = new Dictionary();
23 | _sharedFlowBundles = new Dictionary();
24 |
25 | _bundleBasePath = bundleBasePath;
26 | }
27 |
28 | public IBundle GetApiProxyBundle(string proxyOrProductName)
29 | {
30 | if (!_apiProxyBundles.ContainsKey(proxyOrProductName))
31 | {
32 | _apiProxyBundles.Add(proxyOrProductName, new ApigeeOnlineApiProxyBundle(_bundleBasePath, proxyOrProductName, _apigeeManagementApiService));
33 | }
34 | return _apiProxyBundles[proxyOrProductName];
35 | }
36 |
37 | public IBundle GetSharedFlowBundle(string sharedFlowName)
38 | {
39 | if (!_sharedFlowBundles.ContainsKey(sharedFlowName))
40 | {
41 | _sharedFlowBundles.Add(sharedFlowName, new ApigeeOnlineSharedFlowBundle(_bundleBasePath, sharedFlowName, _apigeeManagementApiService));
42 | }
43 | return _sharedFlowBundles[sharedFlowName];
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Bundles/ApigeeOnlineSharedFlowBundle.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core;
2 | using ApigeeToAzureApimMigrationTool.Core.Interface;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 |
9 | namespace ApigeeToAzureApimMigrationTool.Service.Bundles
10 | {
11 | public class ApigeeOnlineSharedFlowBundle : IBundle
12 | {
13 | private readonly IApigeeManagementApiService _apigeeManagementApiService;
14 | private string _bundleBasePath;
15 | private string _sharedFlowName;
16 | private string? _bundlePath;
17 |
18 | public ApigeeOnlineSharedFlowBundle(string bundleBasePath, string sharedFlowName, IApigeeManagementApiService apigeeManagementApiService)
19 | {
20 | _bundleBasePath = bundleBasePath;
21 | _sharedFlowName = sharedFlowName;
22 | _apigeeManagementApiService = apigeeManagementApiService;
23 | }
24 |
25 | public async Task LoadBundle()
26 | {
27 | //get api metadata
28 | var sharedFlowMetadata = await _apigeeManagementApiService.GetSharedFlowByName(_sharedFlowName);
29 | //get the latest revision
30 | int maxRevision = sharedFlowMetadata.revision.Select(x => int.Parse(x)).Max();
31 | //download api proxy bundle
32 | _bundlePath = await _apigeeManagementApiService.DownloadSharedFlowBundle(_bundleBasePath, _sharedFlowName, maxRevision);
33 | }
34 | public string GetBundlePath()
35 | {
36 | if (string.IsNullOrEmpty(_bundlePath))
37 | {
38 | throw new Exception("Shared flow bundle not loaded. Please load the bundle first");
39 | }
40 |
41 | return Path.Combine(_bundleBasePath, _sharedFlowName, "sharedflowbundle");
42 |
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/ExpressionTranslator.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core.Interface;
2 | using System;
3 | using System.Collections.Generic;
4 | using System.Linq;
5 | using System.Linq.Expressions;
6 | using System.Net;
7 | using System.Text;
8 | using System.Text.RegularExpressions;
9 | using System.Threading.Tasks;
10 | using System.Web;
11 |
12 | namespace ApigeeToAzureApimMigrationTool.Service
13 | {
14 |
15 |
16 | public class ExpressionTranslator : IExpressionTranslator
17 | {
18 | private readonly Dictionary _translationTable;
19 | private readonly Dictionary _translationTableForConditions;
20 |
21 | public ExpressionTranslator()
22 | {
23 | _translationTable = CreateTranslationTable();
24 | _translationTableForConditions = CreateTranslationTableForConditions();
25 | }
26 |
27 | ///
28 | /// Translates the whole string by replacing the keys in the translation table with their corresponding values.
29 | ///
30 | /// The input expression to be translated.
31 | /// The translated expression.
32 | public string TranslateWholeString(string expression)
33 | {
34 | foreach (var item in _translationTable)
35 | expression = expression.Replace(item.Key, item.Value);
36 |
37 | foreach (var item in _translationTableForConditions)
38 | expression = expression.Replace(item.Key, item.Value);
39 |
40 | return expression;
41 | }
42 |
43 | public string TranslateConditionOperator (string expression)
44 | {
45 | foreach (var item in _translationTableForConditions)
46 | expression = expression.Replace(item.Key, item.Value);
47 |
48 | return expression;
49 | }
50 |
51 | ///
52 | /// Checks if the content has variables in it by using a regular expression pattern.
53 | ///
54 | /// The input content to be checked.
55 | /// True if the content has variables, otherwise false.
56 | public bool ContentHasVariablesInIt(string content)
57 | {
58 | const string apigeeVariable = @"{(.*?)}";
59 | return Regex.Matches(content, apigeeVariable).Any();
60 | }
61 |
62 | ///
63 | /// Translates a single item by looking up its value in the translation table.
64 | ///
65 | /// The input expression to be translated.
66 | /// The default value to use in case variable wasn't found.
67 | /// The translated expression if found in the translation table, otherwise the original expression.
68 | public string TranslateSingleItem(string expression, string defaultValue = "")
69 | {
70 | string result = _translationTable.ContainsKey(expression) ? _translationTable[expression] : expression;
71 |
72 | if (result.Contains("request.header."))
73 | {
74 | var headerName = result.Replace("request.header.", "");
75 | result = $"context.Request.Headers.GetValueOrDefault(\"{headerName}\",\"\")";
76 | }
77 |
78 | return result ;
79 | }
80 |
81 | ///
82 | /// Creates the translation table with the predefined key-value pairs.
83 | ///
84 | /// The translation table.
85 | private Dictionary CreateTranslationTable()
86 | {
87 | var expressionList = new Dictionary();
88 | expressionList.Add("request.verb", "context.Operation.Method");
89 | return expressionList;
90 | }
91 |
92 | ///
93 | /// Creates the translation table for conditions with the predefined key-value pairs.
94 | ///
95 | /// The translation table for conditions.
96 | private Dictionary CreateTranslationTableForConditions()
97 | {
98 | var expressionList = new Dictionary();
99 | expressionList.Add(" AND ", " && ");
100 | expressionList.Add(" and ", " && ");
101 | expressionList.Add(" or ", " || ");
102 | expressionList.Add(" OR ", " || ");
103 | expressionList.Add(" = ", " == ");
104 | expressionList.Add(" =| ", " == ");
105 |
106 | return expressionList;
107 | }
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Transformations/AccessControlTransformation.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core.Enum;
2 | using ApigeeToAzureApimMigrationTool.Core.Interface;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Xml.Linq;
9 |
10 |
11 | namespace ApigeeToAzureApimMigrationTool.Service.Transformations
12 | {
13 | public class AccessControlTransformation : IPolicyTransformation
14 | {
15 | public Task> Transform(XElement element, string apigeePolicyName, PolicyDirection policyDirection = PolicyDirection.Inbound)
16 | {
17 | var policyList = new List();
18 | var ipRules = element.Element("IPRules");
19 | var matchRules = ipRules.Elements("MatchRule");
20 | foreach (var matchRule in matchRules)
21 | {
22 | var newPolicy = new XElement("ip-filter");
23 | var action = matchRule.Attribute("action").Value.Equals("DENY", StringComparison.InvariantCultureIgnoreCase) ? "forbid" : "allow";
24 | newPolicy.Add(new XAttribute("action", action));
25 | foreach (var sourceAddress in matchRule.Elements("SourceAddress"))
26 | {
27 | var address = sourceAddress.Value;
28 | var mask = sourceAddress.Attribute("mask")?.Value;
29 | if (mask == null)
30 | {
31 | if (address.StartsWith("{"))
32 | {
33 | newPolicy.Add(new XElement("address", $"@(context.Variables.GetValueOrDefault(\"{address}\",\"\")"));
34 | }
35 | else
36 | newPolicy.Add(new XElement("address", address));
37 | }
38 | else
39 | {
40 | //TODO: add support for variable used in mask
41 | var ipnetwork = System.Net.IPNetwork2.Parse($"{address}/{mask}");
42 | var addressRangeElement = new XElement("address-range");
43 | addressRangeElement.Add(new XAttribute("from", ipnetwork.FirstUsable), new XAttribute("to", ipnetwork.LastUsable));
44 | newPolicy.Add(addressRangeElement);
45 | }
46 | }
47 | policyList.Add(newPolicy);
48 | }
49 | return Task.FromResult>(policyList);
50 | }
51 | }
52 | }
53 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Transformations/BasicAuthenticationTransformation.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core.Enum;
2 | using ApigeeToAzureApimMigrationTool.Core.Interface;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Xml.Linq;
9 |
10 | namespace ApigeeToAzureApimMigrationTool.Service.Transformations
11 | {
12 | public class BasicAuthenticationTransformation : IPolicyTransformation
13 | {
14 | public Task> Transform(XElement element, string apigeePolicyName, PolicyDirection policyDirection = PolicyDirection.Inbound)
15 | {
16 | var policyList = new List();
17 | var basicAuthenticationPolicy = new XElement("authentication-basic");
18 |
19 | var username = element.Element("User")?.Attribute("ref")?.Value;
20 | var password = element.Element("Password")?.Attribute("ref")?.Value;
21 |
22 | string usernameValue;
23 | string passwordValue;
24 |
25 | var operation = element.Element("Operation")?.Value;
26 | if (operation.Equals("Decode", StringComparison.InvariantCultureIgnoreCase))
27 | {
28 | var source = element.Element("Source").Value;
29 | string sourceValue=null;
30 | if (source.StartsWith("request.header."))
31 | {
32 | sourceValue = $"context.Request.Headers.GetValueOrDefault(\"{source.Replace("request.header.", "")}\")";
33 | }
34 |
35 | var userNameVariablePolicy = new XElement("set-variable");
36 | userNameVariablePolicy.Add(new XAttribute("name", username));
37 | userNameVariablePolicy.Add(new XAttribute("value", $@"@{{
38 | Encoding encoding = Encoding.GetEncoding(""iso-8859-1"");
39 | string usernamePassword = encoding.GetString(Convert.FromBase64String({sourceValue}));
40 | int seperatorIndex = usernamePassword.IndexOf(':');
41 | return usernamePassword.Substring(0, seperatorIndex);
42 | }}"));
43 |
44 | policyList.Add(userNameVariablePolicy);
45 |
46 | var PasswordVariablePolicy = new XElement("set-variable");
47 | PasswordVariablePolicy.Add(new XAttribute("name", password));
48 | PasswordVariablePolicy.Add(new XAttribute("value", $@"@{{
49 | Encoding encoding = Encoding.GetEncoding(""iso-8859-1"");
50 | string usernamePassword = encoding.GetString(Convert.FromBase64String({sourceValue}));
51 | int seperatorIndex = usernamePassword.IndexOf(':');
52 | return usernamePassword.Substring(seperatorIndex + 1);
53 | }}"));
54 |
55 | policyList.Add(PasswordVariablePolicy);
56 |
57 | }
58 | else
59 | {
60 | if (username.StartsWith("request.header"))
61 | usernameValue = $"@(context.Request.Headers.GetValueOrDefault(\"{username.Replace("request.header.", "")}\"))";
62 | else if (username.StartsWith("request.queryparam"))
63 | usernameValue = $"@(context.Url.Query.GetValueOrDefault(\"{username.Replace("request.queryparam.", "")}\"))";
64 | else
65 | usernameValue = $"@(context.Variables.GetValueOrDefault(\"{username}\",\"\"))";
66 |
67 | if (password.StartsWith("request.header"))
68 | passwordValue = $"@(context.Request.Headers.GetValueOrDefault(\"{password.Replace("request.header.", "")}\"))";
69 | else if (password.StartsWith("request.queryparam"))
70 | passwordValue = $"@(context.Url.Query.GetValueOrDefault(\"{password.Replace("request.queryparam.", "")}\"))";
71 | else
72 | passwordValue = $"@(context.Variables.GetValueOrDefault(\"{password}\",\"\"))";
73 |
74 | basicAuthenticationPolicy.Add(new XAttribute("username", usernameValue), new XAttribute("password", passwordValue));
75 |
76 | policyList.Add(basicAuthenticationPolicy);
77 | }
78 |
79 | return Task.FromResult>(policyList);
80 | }
81 | }
82 | }
83 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Transformations/ExtractVariablesTransformation.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core.Enum;
2 | using ApigeeToAzureApimMigrationTool.Core.Interface;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.ComponentModel.Design;
6 | using System.Linq;
7 | using System.Linq.Expressions;
8 | using System.Reflection.PortableExecutable;
9 | using System.Text;
10 | using System.Text.RegularExpressions;
11 | using System.Threading.Tasks;
12 | using System.Xml;
13 | using System.Xml.Linq;
14 |
15 | namespace ApigeeToAzureApimMigrationTool.Service.Transformations
16 | {
17 | public class ExtractVariablesTransformation : IPolicyTransformation
18 | {
19 | private readonly IList> _policyVariables;
20 |
21 | ///
22 | /// Initializes a new instance of the class.
23 | ///
24 | /// The list of policy variables.
25 | public ExtractVariablesTransformation(IList> policyVariables)
26 | {
27 | _policyVariables = policyVariables;
28 | }
29 |
30 | ///
31 | /// Transforms the given XML element into a collection of Azure API Management policy elements.
32 | ///
33 | /// The XML element representing the Apigee policy.
34 | /// The name of the Apigee policy.
35 | /// A task that represents the asynchronous transformation operation.
36 | public Task> Transform(XElement element, string apigeePolicyName, PolicyDirection policyDirection = PolicyDirection.Inbound)
37 | {
38 | var apimPolicyElements = new List();
39 | apimPolicyElements.AddRange(ExtractJsonValue(element, apigeePolicyName, policyDirection));
40 | return Task.FromResult(apimPolicyElements.AsEnumerable());
41 | }
42 |
43 | ///
44 | /// Extracts the JSON value from the XML element and creates a new Azure API Management policy element.
45 | ///
46 | /// The XML element representing the Apigee policy.
47 | /// The name of the Apigee policy.
48 | /// The new Azure API Management policy element.
49 | private List ExtractJsonValue(XElement element, string policyName, PolicyDirection policyDirection)
50 | {
51 | List policies = new List();
52 | var variablePrefix = element.Element("VariablePrefix") == null ? string.Empty : element.Element("VariablePrefix").Value;
53 | string sourceName = element.Element("Source")?.Value;
54 | bool isSourceVariable = false;
55 |
56 | if (string.IsNullOrEmpty(sourceName))
57 | {
58 | if (policyDirection == PolicyDirection.Inbound)
59 | sourceName = "Request";
60 | else if (policyDirection == PolicyDirection.Outbound)
61 | sourceName = "Response";
62 | }
63 | else
64 | {
65 | if (!sourceName.Equals("request") && !sourceName.Equals("response"))
66 | isSourceVariable = true;
67 | }
68 |
69 | if (sourceName.Equals("request"))
70 | sourceName = "Request";
71 | if (sourceName.Equals("response"))
72 | sourceName = "Response";
73 |
74 | if (element.Element("JSONPayload") != null)
75 | {
76 | var payloadElement = element.Element("JSONPayload");
77 | foreach (var variableElement in payloadElement.Elements("Variable"))
78 | {
79 | string translatedExpression = string.Empty;
80 | if (isSourceVariable)
81 | {
82 | translatedExpression = "context.Variables.GetValueOrDefault(\"" + sourceName + "\")";
83 | }
84 | else
85 | {
86 | translatedExpression = $"context.{sourceName}.Body.As(preserveContent: true)";
87 | }
88 |
89 | var variableName = variableElement.Attribute("name").Value;
90 | var jsonPath = variableElement.Element("JSONPath").Value;
91 |
92 | string apimExpression = "@{" +
93 | $"JObject json = JObject.Parse({translatedExpression});" +
94 | "var extractedValue = json.SelectToken(\"" + jsonPath + "\");" +
95 | "return extractedValue;" +
96 | "}";
97 | string apimVariableName = string.IsNullOrEmpty(variablePrefix) ? variableName : $"{variablePrefix}.{variableName}";
98 | policies.Add(new XElement("set-variable", new XAttribute("name", apimVariableName), new XAttribute("value", apimExpression)));
99 | _policyVariables.Add(new KeyValuePair(policyName, variableName));
100 | }
101 | }
102 | else if (element.Element("Header") != null)
103 | {
104 | string headerName = element.Element("Header").Attribute("name").Value;
105 | bool IgnoreCaseInPattern = Convert.ToBoolean(element.Element("Header").Element("Pattern").Attribute("ignoreCase").Value);
106 | string patternValue = element.Element("Header").Element("Pattern").Value;
107 |
108 | string patternRegex = @"{(.*?)}";
109 | foreach (Match match in Regex.Matches(patternValue, patternRegex))
110 | {
111 | if (match.Success && match.Groups.Count > 0)
112 | {
113 | string variableName = match.Groups[1].Value;
114 | string variablePattern = match.Groups[0].Value;
115 | string apimExpression = "@{" +
116 | $"string headerValue = \"\"; string pattern=\"{patternValue}\"" +
117 | $"headerValue = context.Request.Headers.GetValueOrDefault(\"{headerName}\");" +
118 | $"headerValue = headerValue.Replace(pattern.Replace(\"{variablePattern}\", \"\"),\"\");" +
119 | "return headerValue;" +
120 | "}";
121 | string apimVariableName = string.IsNullOrEmpty(variablePrefix) ? variableName : $"{variablePrefix}.{variableName}";
122 | policies.Add(new XElement("set-variable", new XAttribute("name", apimVariableName), new XAttribute("value", apimExpression)));
123 | }
124 | }
125 | }
126 | //TODO: support for multi params policies are not yet implemented
127 | else if (element.Elements("QueryParam") != null)
128 | {
129 | string queryParamName = element.Element("QueryParam").Attribute("name").Value;
130 | string patternValue = element.Element("QueryParam").Element("Pattern").Value;
131 | bool IgnoreCaseInPattern = Convert.ToBoolean(element.Element("QueryParam").Element("Pattern").Attribute("ignoreCase").Value);
132 | string patternRegex = @"{(.*?)}";
133 | foreach (Match match in Regex.Matches(patternValue, patternRegex))
134 | {
135 | if (match.Success && match.Groups.Count > 0)
136 | {
137 | string variableName = match.Groups[1].Value;
138 | string variablePattern = match.Groups[0].Value;
139 | string apimExpression = "@{" +
140 | $"string queryParamValue = \"\"; string pattern=\"{patternValue}\"" +
141 | $"queryParamValue = context.Request.Url.Query.GetValueOrDefault(\"{queryParamName}\");" +
142 | $"queryParamValue = queryParamValue.Replace(pattern.Replace(\"{variablePattern}\", \"\"),\"\");" +
143 | "return queryParamValue;" +
144 | "}";
145 | string apimVariableName = string.IsNullOrEmpty(variablePrefix) ? variableName : $"{variablePrefix}.{variableName}";
146 | policies.Add(new XElement("set-variable", new XAttribute("name", apimVariableName), new XAttribute("value", apimExpression)));
147 | }
148 | }
149 | }
150 | else if (element.Elements("XMLPayload") != null)
151 | {
152 | var payloadElement = element.Element("XMLPayload");
153 | string namespaceName = payloadElement.Element("Namespaces").Element("Namespace").Value;
154 | string namespaceNamePrefix = payloadElement.Element("Namespaces").Element("Namespace").Attribute("prefix").Value;
155 |
156 | foreach (var variableElement in payloadElement.Elements("Variable"))
157 | {
158 | string translatedExpression = string.Empty;
159 | if (isSourceVariable)
160 | {
161 | translatedExpression = "context.Variables.GetValueOrDefault(\"" + sourceName + "\")";
162 | }
163 | else
164 | {
165 | translatedExpression = $"context.{sourceName}.Body.As(preserveContent: true)";
166 | }
167 |
168 | var variableName = variableElement.Attribute("name").Value;
169 | var xmlPath = variableElement.Element("XPath").Value;
170 | string apimExpression;
171 | if (!string.IsNullOrEmpty(namespaceName) && !string.IsNullOrEmpty(namespaceNamePrefix))
172 | {
173 | apimExpression = "@{" +
174 | "XmlDocument doc = new XmlDocument();" +
175 | $"doc.LoadXml({translatedExpression});" +
176 | "XmlNamespaceManager nsmgr = new XmlNamespaceManager(doc.NameTable);" +
177 | $"nsmgr.AddNamespace (\"{namespaceNamePrefix}\",\"{namespaceName}\");" +
178 | "var extractedValue = doc.SelectSingleNode(\"" + xmlPath + "\", nsmgr).Value;" +
179 | "return extractedValue;" +
180 | "}";
181 | }
182 | else
183 | {
184 | apimExpression = "@{" +
185 | "XmlDocument doc = new XmlDocument();" +
186 | $"doc.LoadXml({translatedExpression});" +
187 | "var extractedValue = doc.SelectSingleNode(\"" + xmlPath + "\").Value;" +
188 | "return extractedValue;" +
189 | "}";
190 | }
191 | string apimVariableName = string.IsNullOrEmpty(variablePrefix) ? variableName : $"{variablePrefix}.{variableName}";
192 | policies.Add(new XElement("set-variable", new XAttribute("name", apimVariableName), new XAttribute("value", apimExpression)));
193 | _policyVariables.Add(new KeyValuePair(policyName, variableName));
194 | }
195 | }
196 |
197 | return policies;
198 | }
199 | }
200 | }
201 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Transformations/FlowCalloutTransformation.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToApimMigrationTool.Core.Config;
2 | using ApigeeToAzureApimMigrationTool.Core;
3 | using ApigeeToAzureApimMigrationTool.Core.Enum;
4 | using ApigeeToAzureApimMigrationTool.Core.Interface;
5 | using System;
6 | using System.Collections.Generic;
7 | using System.Linq;
8 | using System.Net;
9 | using System.Text;
10 | using System.Threading.Tasks;
11 | using System.Web;
12 | using System.Xml.Linq;
13 |
14 | namespace ApigeeToAzureApimMigrationTool.Service.Transformations
15 | {
16 | public class FlowCalloutTransformation : IPolicyTransformation
17 | {
18 | private readonly IApigeeXmlLoader _apigeeXmlLoader;
19 | private readonly IApimProvider _apimProvider;
20 | private readonly IApigeeManagementApiService _apiService;
21 | private readonly IBundleProvider _bundleProvider;
22 | private ApimConfiguration _apimConfiguration;
23 | private ApigeeConfiguration _apigeeConfiguration;
24 |
25 | private string _sharedFlowName;
26 |
27 | public FlowCalloutTransformation(IApigeeXmlLoader apigeeXmlLoader, IApimProvider apimProvider, IBundleProvider bundleProvider, IApigeeManagementApiService apiService, ApimConfiguration apimConfiguration, ApigeeConfiguration apigeeConfiguration)
28 | {
29 | _apigeeXmlLoader = apigeeXmlLoader;
30 | _apimProvider = apimProvider;
31 | _apiService = apiService;
32 | _bundleProvider = bundleProvider;
33 | _apimConfiguration = apimConfiguration;
34 | _apigeeConfiguration = apigeeConfiguration;
35 | }
36 |
37 | public async Task> Transform(XElement element, string apigeePolicyName, PolicyDirection policyDirection = PolicyDirection.Inbound)
38 | {
39 | var apimPolicies = new List();
40 |
41 | _sharedFlowName = element.Element("SharedFlowBundle").Value;
42 | apimPolicies.Add(IncludeFragment(_sharedFlowName));
43 | return apimPolicies.AsEnumerable();
44 | }
45 |
46 | public async Task DonwloadAndTransformSharedFlow(IApimPolicyTransformer transformer)
47 | {
48 | string sharedFlowBundlePath = await DownloadSharedFlow(_sharedFlowName);
49 | await ImportSharedFlow(_sharedFlowName, _apimProvider.ApimName, transformer);
50 | }
51 |
52 | private async Task DownloadSharedFlow(string sharedFlowName)
53 | {
54 | var sharedFlowMetadata = await _apiService.GetSharedFlowByName(sharedFlowName);
55 | var bundle = _bundleProvider.GetSharedFlowBundle(sharedFlowName);
56 | await bundle.LoadBundle();
57 | return await _apiService.DownloadSharedFlowBundle(bundle.GetBundlePath(), sharedFlowName, sharedFlowMetadata.revision.Select(x => int.Parse(x)).Max());
58 | }
59 |
60 | private async Task ImportSharedFlow(string sharedflowName, string apimName, IApimPolicyTransformer apimPolicyTransformer)
61 | {
62 | var rawPolicyFragment = RawPolicyFragmentXml();
63 |
64 | var sharedFlowBundleXml = _apigeeXmlLoader.LoadSharedFlowBundleXml(sharedflowName);
65 | var sharedFlowElement = sharedFlowBundleXml.Element("SharedFlowBundle");
66 | string sharedFlowName = sharedFlowElement.Attribute("name").Value;
67 | string displayName = sharedFlowElement.Element("DisplayName").Value;
68 | string description = sharedFlowElement.Element("Description").Value;
69 |
70 | var sharedFlows = sharedFlowElement.Element("SharedFlows").Elements("SharedFlow");
71 |
72 | foreach (var sharedFlow in sharedFlows)
73 | {
74 | var sharedFlowXml = _apigeeXmlLoader.LoadSharedFlowXml(sharedFlowName, sharedFlow.Value);
75 | var sharedFlowRootElement = sharedFlowXml.Element("SharedFlow");
76 | var steps = sharedFlowRootElement.Elements("Step");
77 |
78 | await apimPolicyTransformer.TransformPoliciesInCollection(steps, rawPolicyFragment.Root, _apigeeXmlLoader.LoadSharedFlowPolicyXml, apimName, sharedFlowName, _apigeeConfiguration, _apimConfiguration);
79 | await _apimProvider.CreatePolicyFragment(sharedFlowName, apimName, HttpUtility.HtmlDecode(rawPolicyFragment.ToString()), description);
80 | }
81 | }
82 |
83 | private XElement IncludeFragment(string fragmentName)
84 | {
85 | return new XElement("include-fragment", new XAttribute("fragment-id", fragmentName));
86 | }
87 |
88 | private XDocument RawPolicyFragmentXml()
89 | {
90 | string rawFragment = @"";
91 |
92 | return XDocument.Parse(rawFragment);
93 | }
94 |
95 |
96 |
97 | }
98 | }
99 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Transformations/InvalidateCacheTransformation.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core.Enum;
2 | using ApigeeToAzureApimMigrationTool.Core.Interface;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Xml.Linq;
9 |
10 | namespace ApigeeToAzureApimMigrationTool.Service.Transformations
11 | {
12 |
13 | public class InvalidateCacheTransformation : IPolicyTransformation
14 | {
15 | ///
16 | /// Transforms the Apigee cache policy to Azure APIM cache-remove-value policy.
17 | ///
18 | /// The XML element representing the Apigee cache policy.
19 | /// The name of the Apigee policy.
20 | /// The direction of the policy (inbound or outbound).
21 | /// A task that represents the asynchronous transformation operation. The task result contains the transformed Azure APIM policies as a collection of XML elements.
22 | public Task> Transform(XElement element, string apigeePolicyName, PolicyDirection policyDirection = PolicyDirection.Inbound)
23 | {
24 | var apimPolicies = new List();
25 | if (element.Element("CacheKey") != null)
26 | {
27 | apimPolicies.Add(CacheRemoveValue(element, apigeePolicyName));
28 | }
29 | return Task.FromResult(apimPolicies.AsEnumerable());
30 | }
31 |
32 | ///
33 | /// Transforms the Apigee cache key to Azure APIM cache-remove-value key.
34 | ///
35 | /// The XML element representing the Apigee cache policy.
36 | /// The name of the Apigee policy.
37 | /// The transformed Azure APIM cache-remove-value policy as an XML element.
38 | private XElement CacheRemoveValue(XElement element, string policyName)
39 | {
40 | var cacheKey = element.Element("CacheKey");
41 | string prefix = cacheKey.Element("Prefix")?.Value;
42 | string keyFragment = cacheKey.Elements("KeyFragment").First(x => x.Attribute("ref") == null).Value;
43 | string keyFragmentRef = cacheKey.Elements("KeyFragment").First(x => x.Attribute("ref") != null).Attribute("ref").Value;
44 |
45 | string apimCacheKey;
46 | if (!string.IsNullOrEmpty(keyFragment))
47 | apimCacheKey = keyFragment;
48 | else
49 | apimCacheKey = $"(string)context.Variables[\"{keyFragmentRef}\"]";
50 |
51 | if (!string.IsNullOrEmpty(prefix))
52 | apimCacheKey = $"{prefix}__{apimCacheKey}";
53 |
54 | if (!string.IsNullOrEmpty(prefix) && !string.IsNullOrEmpty(keyFragmentRef))
55 | apimCacheKey = $"@(\"{prefix}__\" + context.Variables.GetValueOrDefault(\"{keyFragmentRef}\"))";
56 |
57 | var newPolicy = new XElement("cache-remove-value", new XAttribute("key", apimCacheKey));
58 | return newPolicy;
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Transformations/KeyValueMapTransformation.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core;
2 | using ApigeeToAzureApimMigrationTool.Core.Enum;
3 | using ApigeeToAzureApimMigrationTool.Core.Interface;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Xml.Linq;
10 |
11 | namespace ApigeeToAzureApimMigrationTool.Service.Transformations
12 | {
13 | ///
14 | /// Represents a transformation for converting Apigee key-value map policies to Azure API Management policies.
15 | ///
16 | public class KeyValueMapTransformation : IPolicyTransformation
17 | {
18 | private readonly IApimProvider _apimProvider;
19 | private readonly IApigeeManagementApiService _apigeeService;
20 | private readonly IList> _policyVariables;
21 |
22 | ///
23 | /// Initializes a new instance of the class.
24 | ///
25 | /// The Azure API Management provider.
26 | /// The Apigee management API service.
27 | /// The list of policy variables.
28 | public KeyValueMapTransformation(IApimProvider apimProvider, IApigeeManagementApiService apigeeService, IList> policyVariables)
29 | {
30 | _apimProvider = apimProvider;
31 | _apigeeService = apigeeService;
32 | _policyVariables = policyVariables;
33 | }
34 |
35 | ///
36 | /// Transforms the given Apigee element into a collection of Azure API Management policies.
37 | ///
38 | /// The Apigee element to transform.
39 | /// The name of the Apigee policy.
40 | /// A collection of Azure API Management policies as XElement objects.
41 | public async Task> Transform(XElement apigeeElement, string apigeePolicyName, PolicyDirection policyDirection = PolicyDirection.Inbound)
42 | {
43 | var apimPolicies = new List();
44 |
45 | foreach (var setVariableElement in await SetVariable(apigeeElement, _apigeeService.ProxyName, _apimProvider.ApimName, apigeePolicyName))
46 | apimPolicies.Add(setVariableElement);
47 |
48 | return apimPolicies.AsEnumerable();
49 | }
50 |
51 | ///
52 | /// Sets the variable values based on the Apigee element.Only Get operation is supported by APIM. Put and Delete are not supported.
53 | ///
54 | /// The Apigee element to process.
55 | /// The name of the proxy.
56 | /// The name of the Azure API Management instance.
57 | /// The name of the policy.
58 | /// A collection of Azure API Management policies as XElement objects.
59 | /// only Get operation is supported by APIM. Put and Delete are not supported.
60 | private async Task> SetVariable(XElement element, string proxyName, string apimName, string policyName)
61 | {
62 | XDocument setVariablePolicies = new XDocument();
63 | setVariablePolicies.Add(new XElement("Root"));
64 | var mapIdentifier = element.Attribute("mapIdentifier").Value;
65 |
66 | var getElements = element.Elements("Get");
67 | if (getElements != null)
68 | foreach (var getElement in getElements)
69 | {
70 | var index = getElement.Attribute("index").Value;
71 | string key = string.Empty;
72 | //ref attribute is not supported in APIM as it's not possible to construct the name of the named value in run time.
73 | //Alternative could be a logic apps or function app to read the named value
74 | if (getElement.Element("Key").Element("Parameter").Attribute("ref") != null)
75 | throw new Exception("using the ref attribute to retrieve the name of the parameter in run time is not supported");
76 | else
77 | key = getElement.Element("Key").Element("Parameter").Value;
78 |
79 |
80 | var variableName = getElement.Attribute("assignTo").Value;
81 |
82 | var apigeeKeyValueMap = await _apigeeService.GetKeyValueMapByName(proxyName, _apigeeService.Environment, mapIdentifier);
83 | if (apigeeKeyValueMap != null)
84 | {
85 | var keyValueMapEntry = apigeeKeyValueMap.Entry.FirstOrDefault(x => x.Name.Equals(key));
86 | if (keyValueMapEntry == null)
87 | throw new Exception($"Can't find entry {key} under mapIdentifier {mapIdentifier} in Apigee");
88 |
89 | for (int i = 0; i < apigeeKeyValueMap.Entry.Count; i++)
90 | {
91 | var entry = apigeeKeyValueMap.Entry.ElementAt(i);
92 | await _apimProvider.AddNamedValue(apimName, proxyName, mapIdentifier, key, apigeeKeyValueMap.Encrypted, entry.Value, i + 1);
93 | }
94 | }
95 |
96 | string namedValueName = $"{mapIdentifier}-{key}-{index}";
97 | namedValueName = namedValueName.Replace("_", "-");
98 |
99 | if (namedValueName.Length > 80)
100 | {
101 | namedValueName = namedValueName.Substring(0, 80);
102 | namedValueName = _apimProvider.RemoveTrailingSpecialCharacters(namedValueName);
103 | }
104 |
105 | var policy = new XElement("set-variable", new XAttribute("name", variableName), new XAttribute("value", "{{" + namedValueName + "}}"));
106 | _policyVariables.Add(new KeyValuePair(policyName, variableName));
107 | setVariablePolicies.Root.Add(policy);
108 | }
109 | return setVariablePolicies.Root.Elements();
110 |
111 | }
112 |
113 | }
114 | }
115 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Transformations/LookupCacheTransformation.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core.Enum;
2 | using ApigeeToAzureApimMigrationTool.Core.Interface;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Xml.Linq;
9 |
10 | namespace ApigeeToAzureApimMigrationTool.Service.Transformations
11 | {
12 | public class LookupCacheTransformation : IPolicyTransformation
13 | {
14 | private readonly IList> _policyVariables;
15 |
16 | public LookupCacheTransformation(IList> policyVariables)
17 | {
18 | _policyVariables = policyVariables;
19 | }
20 |
21 | ///
22 | /// Transforms the Apigee LookupCache policy to Azure APIM cache-lookup-value policy.
23 | ///
24 | /// The XML element representing the Apigee LookupCache policy.
25 | /// The name of the Apigee policy.
26 | /// A task that represents the asynchronous transformation operation. The task result contains the transformed Azure APIM policies.
27 | public Task> Transform(XElement element, string apigeePolicyName, PolicyDirection policyDirection = PolicyDirection.Inbound)
28 | {
29 | var apimPolicies = new List();
30 | if (element.Element("CacheKey") != null)
31 | {
32 | apimPolicies.Add(CacheLookupValue(element, apigeePolicyName));
33 | }
34 | return Task.FromResult(apimPolicies.AsEnumerable());
35 | }
36 |
37 | ///
38 | /// Transforms the CacheLookupValue element of the Apigee LookupCache policy to Azure APIM cache-lookup-value policy.
39 | ///
40 | /// The XML element representing the CacheLookupValue element of the Apigee LookupCache policy.
41 | /// The name of the Apigee policy.
42 | /// The transformed Azure APIM cache-lookup-value policy.
43 | private XElement CacheLookupValue(XElement element, string policyName)
44 | {
45 | var cacheKey = element.Element("CacheKey");
46 | string prefix = cacheKey.Element("Prefix")?.Value;
47 | string keyFragment = cacheKey.Elements("KeyFragment").First(x => x.Attribute("ref") == null).Value;
48 | string keyFragmentRef = cacheKey.Elements("KeyFragment").First(x => x.Attribute("ref") != null).Attribute("ref").Value;
49 | string variableName = element.Element("AssignTo").Value;
50 |
51 | string apimCacheKey;
52 | if (!string.IsNullOrEmpty(keyFragment))
53 | apimCacheKey = keyFragment;
54 | else
55 | apimCacheKey = $"(string)context.Variables[\"{keyFragmentRef}\"]";
56 |
57 | if (!string.IsNullOrEmpty(prefix))
58 | apimCacheKey = $"{prefix}__{apimCacheKey}";
59 |
60 | if (!string.IsNullOrEmpty(prefix) && !string.IsNullOrEmpty(keyFragmentRef))
61 | apimCacheKey = $"@(\"{prefix}__\" + context.Variables.GetValueOrDefault(\"{keyFragmentRef}\"))";
62 |
63 | var newPolicy = new XElement("cache-lookup-value", new XAttribute("key", apimCacheKey), new XAttribute("variable-name", variableName));
64 | _policyVariables.Add(new KeyValuePair(policyName, variableName));
65 | return newPolicy;
66 | }
67 | }
68 | }
69 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Transformations/NullTransformation.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core.Enum;
2 | using ApigeeToAzureApimMigrationTool.Core.Interface;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Xml.Linq;
9 |
10 | namespace ApigeeToAzureApimMigrationTool.Service.Transformations
11 | {
12 | public class NullTransformation : IPolicyTransformation
13 | {
14 | public Task> Transform(XElement element, string apigeePolicyName, PolicyDirection policyDirection = PolicyDirection.Inbound)
15 | {
16 | // Return empty list
17 | return Task.FromResult(new List().AsEnumerable());
18 | }
19 | }
20 | }
21 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Transformations/OAuthV2Transformation.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToApimMigrationTool.Core.Config;
2 | using ApigeeToAzureApimMigrationTool.Core.Enum;
3 | using ApigeeToAzureApimMigrationTool.Core.Interface;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Xml.Linq;
10 |
11 | namespace ApigeeToAzureApimMigrationTool.Service.Transformations
12 | {
13 |
14 |
15 | public class OAuthV2Transformation : IPolicyTransformation
16 | {
17 | private ApimConfiguration _apimConfiguration;
18 | public OAuthV2Transformation(ApimConfiguration apimConfiguration)
19 | {
20 | _apimConfiguration = apimConfiguration;
21 | }
22 | public Task> Transform(XElement element, string apigeePolicyName, PolicyDirection policyDirection = PolicyDirection.Inbound)
23 | {
24 | var apimPolicies = new List
25 | {
26 | OAuthV2(element, apigeePolicyName)
27 | };
28 |
29 | return Task.FromResult(apimPolicies.AsEnumerable());
30 | }
31 | private XElement OAuthV2(XElement element, string policyName)
32 | {
33 | //Only VerifyAccessToken operation is supported
34 | var operation = element.Element("Operation")?.Value;
35 | var name = element.Attribute("name")?.Value;
36 | if (!operation.Equals("VerifyAccessToken", StringComparison.InvariantCultureIgnoreCase))
37 | {
38 | throw new NotSupportedException($"Only VerifyAccessToken operation is supported for OAuthV2 policy. Policy name: {name}");
39 | }
40 |
41 | var displayName = element.Element("DisplayName")?.Value;
42 | string accessTokenPrefix = element.Element("AccessTokenPrefix")?.Value;
43 | if (string.IsNullOrEmpty(accessTokenPrefix))
44 | accessTokenPrefix = "Bearer";
45 |
46 |
47 | // query-parameter-name is not supported yet. JWT can only be included as a header
48 | string accessTokenHeaderName = element.Element("AccessToken")?.Value;
49 | if (string.IsNullOrEmpty(accessTokenHeaderName))
50 | accessTokenHeaderName = "Authorization";
51 |
52 | var newPolicy = new XElement("validate-jwt",
53 | new XAttribute("header-name", accessTokenHeaderName),
54 | new XAttribute("failed-validation-httpcode", "401"),
55 | new XAttribute("failed-validation-error-message", "Unauthorized. Access token is missing or invalid."),
56 | new XElement("openid-config", new XAttribute("url", $"https://login.microsoftonline.com/{_apimConfiguration.OAuthTenantId}/v2.0/.well-known/openid-configuration"))
57 | );
58 |
59 | if (!string.IsNullOrEmpty(_apimConfiguration.OAuthAudiences))
60 | {
61 | newPolicy.Element("validate-jwt").Add(new XElement("audiences"));
62 |
63 | var audienceArray = _apimConfiguration.OAuthAudiences.Split(',');
64 | foreach (string audience in audienceArray)
65 | {
66 | newPolicy.Element("validate-jwt").Element("audiences").Add(new XElement("audience", audience));
67 | }
68 | }
69 |
70 | if (!string.IsNullOrEmpty(_apimConfiguration.OAuthIssuers))
71 | {
72 | newPolicy.Element("validate-jwt").Add(new XElement("issuers"));
73 |
74 | var issuerArray = _apimConfiguration.OAuthIssuers.Split(',');
75 | foreach (string issuer in issuerArray)
76 | {
77 | newPolicy.Element("validate-jwt").Element("issuers").Add(new XElement("issuer", issuer));
78 | }
79 | }
80 |
81 | string scopeClaimName = "scope";
82 | if (!string.IsNullOrEmpty(_apimConfiguration.OAuthScopeClaimName))
83 | scopeClaimName = _apimConfiguration.OAuthScopeClaimName;
84 |
85 | var scope = element.Element("Scope")?.Value;
86 | if (!string.IsNullOrEmpty(scope))
87 | {
88 | newPolicy.Element("validate-jwt").Element("required-claims").Add(
89 | new XElement("claim", scope,
90 | new XAttribute("name", scopeClaimName),
91 | new XAttribute("match", "any"),
92 | new XAttribute("separator", " ")
93 | )
94 | );
95 | }
96 |
97 | return newPolicy;
98 | }
99 |
100 | }
101 | }
102 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Transformations/PolicyTransformationFactory.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToApimMigrationTool.Core.Config;
2 | using ApigeeToAzureApimMigrationTool.Core;
3 | using ApigeeToAzureApimMigrationTool.Core.Interface;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Xml.Linq;
10 |
11 | namespace ApigeeToAzureApimMigrationTool.Service.Transformations
12 | {
13 | public class PolicyTransformationFactory : IPolicyTransformationFactory
14 | {
15 | private readonly IApigeeXmlLoader _apigeeXmlLoader;
16 | private readonly IApigeeManagementApiService _apigeeService;
17 | private readonly IApimProvider _apimProvider;
18 | private readonly IBundleProvider _bundleProvider;
19 | private readonly IExpressionTranslator _expressionTranslator;
20 | public PolicyTransformationFactory(IApigeeManagementApiService apigeeService, IApimProvider apimProvider, IBundleProvider bundleProvider, IApigeeXmlLoader apigeeXmlLoader, IExpressionTranslator expressionTranslator)
21 | {
22 | _apigeeService = apigeeService;
23 | _apimProvider = apimProvider;
24 | _apigeeXmlLoader = apigeeXmlLoader;
25 | _bundleProvider = bundleProvider;
26 | _expressionTranslator = expressionTranslator;
27 | }
28 | public IPolicyTransformation GetTransformationForPolicy(string policyName, IList> policyVariables, ApigeeConfiguration apigeeConfiguration, ApimConfiguration apimConfig)
29 | {
30 | switch (policyName)
31 | {
32 | case "AssignMessage":
33 | return new AssignMessageTransformation(_expressionTranslator);
34 | case "LookupCache":
35 | return new LookupCacheTransformation(policyVariables);
36 | case "KeyValueMapOperations":
37 | return new KeyValueMapTransformation(_apimProvider, _apigeeService, policyVariables);
38 | case "VerifyJWT":
39 | return new VerifyJwtTransformation(policyVariables);
40 | case "ServiceCallout":
41 | return new ServiceCalloutTransformation(_apigeeService, _apimProvider, _expressionTranslator);
42 | case "ExtractVariables":
43 | return new ExtractVariablesTransformation(policyVariables);
44 | case "OAuthV2":
45 | return new OAuthV2Transformation(apimConfig);
46 | case "PopulateCache":
47 | return new PopulateCacheTransformation(policyVariables);
48 | case "InvalidateCache":
49 | return new InvalidateCacheTransformation();
50 | case "FlowCallout":
51 | return new FlowCalloutTransformation(_apigeeXmlLoader, _apimProvider, _bundleProvider, _apigeeService, apimConfig, apigeeConfiguration);
52 | case "RaiseFault":
53 | return new RaiseFaultTransformation(_expressionTranslator);
54 | case "BasicAuthentication":
55 | return new BasicAuthenticationTransformation();
56 | case "SpikeArrest":
57 | return new SpikeArrestTransformation(_expressionTranslator);
58 | case "AccessControl":
59 | return new AccessControlTransformation();
60 | default:
61 | return new NullTransformation();
62 |
63 | }
64 | }
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Transformations/PopulateCacheTransformation.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core.Enum;
2 | using ApigeeToAzureApimMigrationTool.Core.Interface;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Globalization;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Threading.Tasks;
9 | using System.Xml.Linq;
10 |
11 | namespace ApigeeToAzureApimMigrationTool.Service.Transformations
12 | {
13 |
14 | public class PopulateCacheTransformation : IPolicyTransformation
15 | {
16 | private readonly IList> _policyVariables;
17 |
18 | public PopulateCacheTransformation(IList> policyVariables)
19 | {
20 | _policyVariables = policyVariables;
21 | }
22 |
23 | ///
24 | /// Transforms the Apigee policy to Azure API Management policies.
25 | ///
26 | /// The Apigee policy XML element.
27 | /// The name of the Apigee policy.
28 | /// The transformed Azure API Management policies as a collection of XML elements.
29 | public Task> Transform(XElement element, string apigeePolicyName, PolicyDirection policyDirection = PolicyDirection.Inbound)
30 | {
31 | var apimPolicies = new List();
32 |
33 | apimPolicies.Add(CacheStoreValue(element, apigeePolicyName));
34 |
35 | return Task.FromResult(apimPolicies.AsEnumerable());
36 | }
37 |
38 | ///
39 | /// Transforms the CacheStoreValue policy.
40 | ///
41 | /// The Apigee policy XML element.
42 | /// The name of the Apigee policy.
43 | /// The transformed Azure API Management policy as an XML element.
44 | private XElement CacheStoreValue(XElement element, string policyName)
45 | {
46 | var cacheKey = element.Element("CacheKey");
47 | string prefix = cacheKey.Element("Prefix")?.Value;
48 | string keyFragment = cacheKey.Elements("KeyFragment").First(x => x.Attribute("ref") == null).Value;
49 | string keyFragmentRef = cacheKey.Elements("KeyFragment").First(x => x.Attribute("ref") != null).Attribute("ref").Value;
50 |
51 | string timeout = element.Element("ExpirySettings").Element("TimeoutInSec")?.Value;
52 | string timeoutRef = element.Element("ExpirySettings").Element("TimeoutInSec")?.Attribute("ref")?.Value;
53 | string expiryDate = element.Element("ExpirySettings").Element("ExpiryDate")?.Value;
54 | string expiryDateRef = element.Element("ExpirySettings").Element("ExpiryDate")?.Attribute("ref")?.Value;
55 | string timeOfDay = element.Element("ExpirySettings").Element("TimeOfDay")?.Value;
56 | string timeOfDayRef = element.Element("ExpirySettings").Element("TimeOfDay")?.Attribute("ref")?.Value;
57 |
58 | string timeOutSeconds = "30";
59 | if (!string.IsNullOrEmpty(expiryDate))
60 | {
61 | string[] formats = { "MM-dd-yyyy" };
62 | DateTime cacheExpiryDate = DateTime.ParseExact(expiryDate, formats, new CultureInfo("en-US"), DateTimeStyles.None);
63 | timeOutSeconds = (cacheExpiryDate - DateTime.Now).Seconds.ToString();
64 | }
65 | else if (!string.IsNullOrEmpty(expiryDateRef))
66 | {
67 | timeOutSeconds = $"@((DateTime.Parse(context.Variables.GetValueOrDefault(\"{expiryDateRef}\")) - DateTime.Now).Seconds.ToString())";
68 | }
69 | else if (!string.IsNullOrEmpty(timeOfDay))
70 | {
71 | var time = TimeSpan.Parse(timeOfDay);
72 | var cacheExpiryDate = DateTime.Today.Add(time);
73 | timeOutSeconds = (cacheExpiryDate - DateTime.Now).Seconds.ToString();
74 | }
75 | else if (!string.IsNullOrEmpty(timeOfDayRef))
76 | {
77 | timeOutSeconds = $"@{{ var time = TimeSpan.Parse(context.Variables.GetValueOrDefault(\"{timeOfDayRef}\")); var cacheExpiryDate = DateTime.Today.Add(time); return (cacheExpiryDate - DateTime.Now).Seconds.ToString(); }}";
78 | }
79 | else if (!string.IsNullOrEmpty(timeout))
80 | {
81 | timeOutSeconds = timeout;
82 | }
83 | else if (!string.IsNullOrEmpty(timeoutRef))
84 | {
85 | timeOutSeconds = $"@(context.Variables.GetValueOrDefault(\"{timeoutRef}\"))";
86 | }
87 | else
88 | {
89 | throw new NotSupportedException("At least one of the following elements need to be defined within the ExpirySettings element of PopulateCache policy. TimeoutInSec, ExpiryDate or TimeOfDay");
90 | }
91 |
92 | string variableName = element.Element("Source").Value;
93 |
94 | string apimCacheKey;
95 | if (!string.IsNullOrEmpty(keyFragment))
96 | apimCacheKey = keyFragment;
97 | else
98 | apimCacheKey = $"(string)context.Variables[\"{keyFragmentRef}\"]";
99 |
100 | if (!string.IsNullOrEmpty(prefix))
101 | apimCacheKey = $"{prefix}__{apimCacheKey}";
102 |
103 | if(!string.IsNullOrEmpty(prefix) && !string.IsNullOrEmpty(keyFragmentRef))
104 | apimCacheKey = $"@(\"{prefix}__\" + context.Variables.GetValueOrDefault(\"{keyFragmentRef}\"))";
105 |
106 | var newPolicy = new XElement("cache-store-value", new XAttribute("key", apimCacheKey), new XAttribute("value", $"@((string)context.Variables[\"{variableName}\"])"), new XAttribute("duration", timeOutSeconds));
107 | _policyVariables.Add(new KeyValuePair(policyName, variableName));
108 | return newPolicy;
109 | }
110 |
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Transformations/RaiseFaultTransformation.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core.Enum;
2 | using ApigeeToAzureApimMigrationTool.Core.Interface;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Xml.Linq;
9 |
10 | namespace ApigeeToAzureApimMigrationTool.Service.Transformations
11 | {
12 | public class RaiseFaultTransformation : AssignMessageTransformation, IPolicyTransformation
13 | {
14 | public RaiseFaultTransformation(IExpressionTranslator expressionTranslator) : base(expressionTranslator)
15 | {
16 | }
17 |
18 | public Task> Transform(XElement apigeePolicyElement, string apigeePolicyName)
19 | {
20 | var policyList = new List();
21 | var returnResponsePolicy = new XElement("return-response");
22 | var apimPolicies = BuildApimPolicyCollection(apigeePolicyElement.Element("FaultResponse")).ToList();
23 | string statusCode = "500";
24 | string reasonPhrase = "Server Error";
25 |
26 | string faultReason = string.Empty;
27 | if (apigeePolicyElement.Element("Set").Element("StatusCode") != null)
28 | statusCode = apigeePolicyElement.Element("Set").Element("StatusCode").Value;
29 |
30 | if (apigeePolicyElement.Element("Set").Element("ReasonPhrase") != null)
31 | reasonPhrase = apigeePolicyElement.Element("Set").Element("ReasonPhrase").Value;
32 |
33 |
34 | apimPolicies.Add(new XElement("set-status", new XAttribute("code", statusCode), new XAttribute("reason", reasonPhrase)));
35 |
36 | foreach(var policy in apimPolicies)
37 | {
38 | returnResponsePolicy.Add(policy);
39 | }
40 |
41 | policyList.Add(returnResponsePolicy);
42 | return Task.FromResult>(policyList);
43 |
44 | }
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Transformations/ServiceCalloutTransformation.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core;
2 | using ApigeeToAzureApimMigrationTool.Core.Enum;
3 | using ApigeeToAzureApimMigrationTool.Core.Interface;
4 | using System;
5 | using System.Collections.Generic;
6 | using System.Linq;
7 | using System.Text;
8 | using System.Text.RegularExpressions;
9 | using System.Threading.Tasks;
10 | using System.Xml.Linq;
11 |
12 | namespace ApigeeToAzureApimMigrationTool.Service.Transformations
13 | {
14 | public class ServiceCalloutTransformation : AssignMessageTransformation, IPolicyTransformation
15 | {
16 | private readonly IApigeeManagementApiService _apigeeService;
17 | private readonly IApimProvider _apimProvider;
18 | private readonly IExpressionTranslator _expressionTranslator;
19 |
20 | public ServiceCalloutTransformation(IApigeeManagementApiService apigeeService, IApimProvider apimProvider, IExpressionTranslator expressionTranslator) : base(expressionTranslator)
21 | {
22 | _apigeeService = apigeeService;
23 | _apimProvider = apimProvider;
24 | _expressionTranslator = expressionTranslator;
25 | }
26 |
27 | public async Task> Transform(XElement element, string apigeePolicyName, PolicyDirection policyDirection = PolicyDirection.Inbound)
28 | {
29 | var apimPolicies = new List();
30 |
31 | var apimSendRequestPolicy = await SendRequest(element, _apimProvider.ApimUrl, _apigeeService.Environment);
32 |
33 | apimPolicies.Add(apimSendRequestPolicy);
34 |
35 | return apimPolicies.AsEnumerable();
36 | }
37 | private async Task SendRequest(XElement element, string apimUrl, string? environment)
38 | {
39 | string requestVariable = element.Element("Request").Attribute("variable").Value;
40 | string responseVariable = element.Element("Response").Value;
41 | string continueOnError = element.Attribute("continueOnError").Value;
42 | string timeout = element.Element("Timeout")?.Value ?? "60";
43 |
44 | var newPolicy = new XElement("send-request", new XAttribute("mode", $"new"), new XAttribute("response-variable-name", responseVariable),
45 | new XAttribute("timeout", timeout), new XAttribute("ignore-error", $"{continueOnError}"));
46 |
47 | string url = string.Empty;
48 | string targetServerName = string.Empty;
49 |
50 | if (element.Element("LocalTargetConnection") != null && element.Element("LocalTargetConnection").Element("Path") != null)
51 | url = element.Element("LocalTargetConnection").Element("Path").Value;
52 | else if (element.Element("HTTPTargetConnection") != null && element.Element("HTTPTargetConnection").Element("URL") != null)
53 | url = element.Element("HTTPTargetConnection").Element("URL").Value;
54 | else if (element.Element("HTTPTargetConnection") != null && element.Element("HTTPTargetConnection").Element("LoadBalancer") != null
55 | && element.Element("HTTPTargetConnection").Element("LoadBalancer").Elements("Server").Any())
56 | {
57 |
58 | targetServerName = element.Element("HTTPTargetConnection").Element("LoadBalancer").Elements("Server").First().Attribute("name").Value;
59 | if (string.IsNullOrEmpty(environment))
60 | throw new Exception($"service callout policy is using a load balancer as target connection. Environment input parameter must be provided in order to migrate target server {targetServerName}");
61 | var targetServerResponse = await _apigeeService.GetTargetServerByName(targetServerName, environment);
62 | if (targetServerResponse == null)
63 | throw new Exception($"Can't read Target Server information for {targetServerName} in the {environment} env");
64 | string protocol = "http://";
65 | string port = string.Empty;
66 | if (targetServerResponse.SSLInfo.Enabled)
67 | protocol = "https://";
68 | if (!(new int[] { 80, 443 }).Contains(targetServerResponse.Port))
69 | port = $":{targetServerResponse.Port}";
70 |
71 | url = $"{protocol}{targetServerResponse.Host}{port}";
72 | }
73 |
74 | if (url.StartsWith('/'))
75 | url = apimUrl + url;
76 |
77 | if (element.Element("Request")?.Element("Set")?.Element("Path") != null)
78 | {
79 | string path = element.Element("Request").Element("Set").Element("Path").Value;
80 | if (path.StartsWith("{"))
81 | {
82 | url = url + "/" + $"@((string)context.Variables[\"{path.Replace("{", "").Replace("}", "")}\"])";
83 | }
84 | }
85 |
86 | newPolicy.Add(new XElement("set-url", url));
87 |
88 | string verb = element.Element("Request")?.Element("Set")?.Element("Verb") != null ? element.Element("Request").Element("Set").Element("Verb").Value : "GET";
89 | newPolicy.Add(new XElement("set-method", verb));
90 |
91 | var apimPolicies = BuildApimPolicyCollection(element.Element("Request")).ToList();
92 |
93 | foreach (var policy in apimPolicies)
94 | {
95 | newPolicy.Add(policy);
96 | }
97 |
98 | return newPolicy;
99 | }
100 |
101 | }
102 | }
103 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Transformations/SpikeArrestTransformation.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core.Enum;
2 | using ApigeeToAzureApimMigrationTool.Core.Interface;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading;
8 | using System.Threading.Tasks;
9 | using System.Xml.Linq;
10 |
11 | namespace ApigeeToAzureApimMigrationTool.Service.Transformations
12 | {
13 | public class SpikeArrestTransformation : IPolicyTransformation
14 | {
15 | private readonly IExpressionTranslator _expressionTranslator;
16 |
17 | public SpikeArrestTransformation(IExpressionTranslator expressionTranslator)
18 | {
19 | _expressionTranslator = expressionTranslator;
20 | }
21 |
22 | public Task> Transform(XElement element, string apigeePolicyName, PolicyDirection policyDirection = PolicyDirection.Inbound)
23 | {
24 | var policyList = new List();
25 |
26 | string rateExpression;
27 | string renewalPeriodExpression = "1";
28 |
29 | string rate = element.Element("Rate")?.Value;
30 | if (string.IsNullOrEmpty(rate))
31 | {
32 | rate = element.Element("Rate").Attribute("ref").Value;
33 | rateExpression = $"@{{ var value = {_expressionTranslator.TranslateSingleItem(rate)}; return value.Contains(\"pm\") ? int.Parse(value.Replace(\"pm\", \"\")) / 60 : value.Replace(\"ps\", \"\"); }}";
34 | renewalPeriodExpression = $"@{{ var value = {_expressionTranslator.TranslateSingleItem(rate)}; return value.Contains(\"pm\") ? 60 : 1 }}";
35 | }
36 | else
37 | {
38 | if (rate.Contains("pm"))
39 | {
40 | renewalPeriodExpression = "60";
41 | rateExpression = (int.Parse(rate.Replace("pm", "")) / 60).ToString();
42 | }
43 | else
44 | rateExpression = (int.Parse(rate.Replace("ps", ""))).ToString();
45 | }
46 |
47 | string counterKey = element.Element("Identifier")?.Attribute("ref")?.Value;
48 |
49 | XElement rateLimitPolicy;
50 | if (!string.IsNullOrEmpty(counterKey))
51 | rateLimitPolicy = new XElement("rate-limit-by-key", new XAttribute("calls", rateExpression), new XAttribute("renewal-period", renewalPeriodExpression),
52 | new XAttribute("counter-key", $"@({_expressionTranslator.TranslateSingleItem(counterKey)})"));
53 | else
54 | rateLimitPolicy = new XElement("rate-limit", new XAttribute("calls", rateExpression), new XAttribute("renewal-period", renewalPeriodExpression));
55 |
56 | policyList.Add(rateLimitPolicy);
57 | return Task.FromResult>(policyList);
58 |
59 | }
60 | }
61 | }
62 |
--------------------------------------------------------------------------------
/ApigeeToAzureApimMigrationTool.Logic/Transformations/VerifyJwtTransformation.cs:
--------------------------------------------------------------------------------
1 | using ApigeeToAzureApimMigrationTool.Core.Enum;
2 | using ApigeeToAzureApimMigrationTool.Core.Interface;
3 | using System;
4 | using System.Collections.Generic;
5 | using System.Linq;
6 | using System.Text;
7 | using System.Threading.Tasks;
8 | using System.Xml.Linq;
9 |
10 | namespace ApigeeToAzureApimMigrationTool.Service.Transformations
11 | {
12 | public class VerifyJwtTransformation : IPolicyTransformation
13 | {
14 | private readonly IList> _policyVariables;
15 |
16 | public VerifyJwtTransformation(IList> policyVariables)
17 | {
18 | _policyVariables = policyVariables;
19 | }
20 | public Task> Transform(XElement element, string apigeePolicyName, PolicyDirection policyDirection = PolicyDirection.Inbound)
21 | {
22 | var apimPolicies = new List
23 | {
24 | ValidateJwt(element)
25 | };
26 |
27 | return Task.FromResult(apimPolicies.AsEnumerable());
28 | }
29 | private XElement ValidateJwt(XElement element)
30 | {
31 | var token = element.Element("Source").Value;
32 | var key = element.Element("PublicKey")?.Element("Value")?.Attribute("ref")?.Value;
33 | if (key == null)
34 | throw new NotSupportedException("VerifyJWT policy without defined public key is not supported");
35 |
36 | var decryptionKeyelement = new XElement("issuer-signing-keys");
37 | decryptionKeyelement.Add(new XElement("key", $"@(context.Variables.GetValueOrDefault(\"{key}\",\"\"))"));
38 | string outputVariableName = $"{token}_validated";
39 | var newPolicy = new XElement("validate-jwt", new XAttribute("token-value", $"@(context.Variables.GetValueOrDefault(\"{token}\",\"\"))"), decryptionKeyelement,
40 | new XAttribute("output-token-variable-name", outputVariableName));
41 | _policyVariables.Add(new KeyValuePair(element.Attribute("name").Value, outputVariableName));
42 |
43 | if(element.Element("IgnoreInvalidToken") != null)
44 | {
45 | newPolicy.Add(new XAttribute("ignore-error", "true"));
46 | }
47 |
48 |
49 |
50 | return newPolicy;
51 | }
52 |
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/CODEOWNERS:
--------------------------------------------------------------------------------
1 | * @pfekrati @jaspecla
2 |
--------------------------------------------------------------------------------
/CODE_OF_CONDUCT.md:
--------------------------------------------------------------------------------
1 | # Microsoft Open Source Code of Conduct
2 |
3 | This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
4 |
5 | Resources:
6 |
7 | - [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
8 | - [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
9 | - Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
10 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) Microsoft Corporation.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE
22 |
--------------------------------------------------------------------------------
/Roadmap.md:
--------------------------------------------------------------------------------
1 | # Elevating the Apigee to APIM Roadmap Experience
2 |
3 | Welcome to [the comprehensive roadmap](https://github.com/orgs/Azure/projects/622/views/2) that grants you a panoramic insight into the ongoing developments within this repository. This structured guide is designed to streamline and enhance your understanding of the intricate journey from Apigee to APIM.
4 |
5 | ## Navigating the Roadmap
6 |
7 | Every element embedded in this roadmap is meticulously documented as an issue, with discernable labels providing crucial insights. These labels serve as a beacon, guiding you through the dynamic phases of our release cycle and shedding light on the anticipated milestones.
8 |
9 | ### Guide to Release Phases
10 |
11 | - **exploring**: Delving into the depths, assessing potential value and feasibility.
12 | - **in design**: Crafting the intricate specifications and design nuances.
13 | - **preview**: Unveiling the feature to a select audience for an exclusive preview.
14 | - **GA**: Grand unveiling, launching the feature to all users for widespread adoption.
15 |
16 | ### Product SKUs Insight
17 |
18 | Our roadmap is intricately interwoven with various product SKUs, each catering to specific facets of our overarching objectives.
19 |
20 | - **Product**
21 | - **Subscription**
22 | - **Policies**
23 | - **APIs**
24 |
25 | ## The Roadmap Unveiled
26 |
27 | As a feature evolves through its lifecycle, it is adorned with labels signifying the product SKUs it aligns with. Following delivery, the distinguished **shipped** label is affixed to the corresponding issue, officially marking its closure. A comment accompanies this closure, providing a seamless link to the pertinent release details.
28 |
29 | ## Orchestrating the Process
30 |
31 | This roadmap doesn't merely exist; it thrives within the framework of a meticulously reviewed process, with labels orchestrating its governance. These labels serve as guardians, tracking the crucial steps within the governance process:
32 |
33 | - **reviewed**: Scrutinized, ensuring a comprehensive understanding of the feature scope.
34 | - **endorsed**: Resources allocated, paving the way for progression.
35 |
36 | This roadmap guides you with confidence, as it not only outlines a path but also considers every detail, ensuring a smooth transition from discovery to widespread use.
37 |
--------------------------------------------------------------------------------
/SECURITY.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | ## Security
4 |
5 | Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet) and [Xamarin](https://github.com/xamarin).
6 |
7 | If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below.
8 |
9 | ## Reporting Security Issues
10 |
11 | **Please do not report security vulnerabilities through public GitHub issues.**
12 |
13 | Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report).
14 |
15 | If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com). If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp).
16 |
17 | You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc).
18 |
19 | Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
20 |
21 | * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
22 | * Full paths of source file(s) related to the manifestation of the issue
23 | * The location of the affected source code (tag/branch/commit or direct URL)
24 | * Any special configuration required to reproduce the issue
25 | * Step-by-step instructions to reproduce the issue
26 | * Proof-of-concept or exploit code (if possible)
27 | * Impact of the issue, including how an attacker might exploit the issue
28 |
29 | This information will help us triage your report more quickly.
30 |
31 | If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs.
32 |
33 | ## Preferred Languages
34 |
35 | We prefer all communications to be in English.
36 |
37 | ## Policy
38 |
39 | Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd).
40 |
41 |
42 |
--------------------------------------------------------------------------------
/SUPPORT.md:
--------------------------------------------------------------------------------
1 | # TODO: The maintainer of this repo has not yet edited this file
2 |
3 | **REPO OWNER**: Do you want Customer Service & Support (CSS) support for this product/project?
4 |
5 | - **No CSS support:** Fill out this template with information about how to file issues and get help.
6 | - **Yes CSS support:** Fill out an intake form at [aka.ms/onboardsupport](https://aka.ms/onboardsupport). CSS will work with/help you to determine next steps.
7 | - **Not sure?** Fill out an intake as though the answer were "Yes". CSS will help you decide.
8 |
9 | *Then remove this first heading from this SUPPORT.MD file before publishing your repo.*
10 |
11 | # Support
12 |
13 | ## How to file issues and get help
14 |
15 | This project uses GitHub Issues to track bugs and feature requests. Please search the existing
16 | issues before filing new issues to avoid duplicates. For new issues, file your bug or
17 | feature request as a new Issue.
18 |
19 | For help and questions about using this project, please **REPO MAINTAINER: INSERT INSTRUCTIONS HERE
20 | FOR HOW TO ENGAGE REPO OWNERS OR COMMUNITY FOR HELP. COULD BE A STACK OVERFLOW TAG OR OTHER
21 | CHANNEL. WHERE WILL YOU HELP PEOPLE?**.
22 |
23 | ## Microsoft Support Policy
24 |
25 | Support for this **PROJECT or PRODUCT** is limited to the resources listed above.
26 |
--------------------------------------------------------------------------------