diff --git a/lib/components/AuthScopes/auth-scopes.html b/lib/components/AuthScopes/auth-scopes.html
new file mode 100644
index 00000000..3d4adb82
--- /dev/null
+++ b/lib/components/AuthScopes/auth-scopes.html
@@ -0,0 +1,13 @@
+
+
+
diff --git a/lib/components/AuthScopes/auth-scopes.ts b/lib/components/AuthScopes/auth-scopes.ts
new file mode 100644
index 00000000..b73d4a39
--- /dev/null
+++ b/lib/components/AuthScopes/auth-scopes.ts
@@ -0,0 +1,31 @@
+'use strict';
+import { Component, Input, ChangeDetectionStrategy, OnInit } from '@angular/core';
+import { BaseComponent, SpecManager } from '../base';
+import { SchemaHelper } from '../../services/schema-helper.service';
+import { ComponentParser } from '../../services/component-parser.service';
+
+@Component({
+ selector: 'auth-scopes',
+ templateUrl: './auth-scopes.html',
+ changeDetection: ChangeDetectionStrategy.OnPush
+})
+export class AuthScopes extends BaseComponent implements OnInit {
+ @Input() pointer:string;
+
+ public scopes: any;
+
+ constructor(specMgr:SpecManager) {
+ super(specMgr);
+ }
+
+ init() {
+ let theScopes = this.specMgr.getOperationScopes(this.pointer);
+ if (theScopes.length) {
+ this.scopes = {scopes: theScopes}
+ }
+ }
+
+ ngOnInit() {
+ this.preinit();
+ }
+}
diff --git a/lib/components/Operation/operation.html b/lib/components/Operation/operation.html
index 3ddea4f5..9eba10ae 100644
--- a/lib/components/Operation/operation.html
+++ b/lib/components/Operation/operation.html
@@ -2,6 +2,7 @@
diff --git a/lib/components/index.ts b/lib/components/index.ts
index 719d20d6..fe5a48e5 100644
--- a/lib/components/index.ts
+++ b/lib/components/index.ts
@@ -8,6 +8,7 @@ import { ParamsList } from './ParamsList/params-list';
import { RequestSamples } from './RequestSamples/request-samples';
import { ResponsesList } from './ResponsesList/responses-list';
import { ResponsesSamples } from './ResponsesSamples/responses-samples';
+import { AuthScopes} from './AuthScopes/auth-scopes';
import { SchemaSample } from './SchemaSample/schema-sample';
import { SideMenu, SideMenuItems } from './SideMenu/side-menu';
import { OperationsList } from './OperationsList/operations-list';
@@ -23,10 +24,10 @@ import { Redoc } from './Redoc/redoc';
export const REDOC_DIRECTIVES = [
ApiInfo, ApiLogo, JsonSchema, JsonSchemaLazy, ParamsList, RequestSamples, ResponsesList,
- ResponsesSamples, SchemaSample, SideMenu, OperationsList, Operation, Warnings, Redoc, SecurityDefinitions,
+ ResponsesSamples, AuthScopes, SchemaSample, SideMenu, OperationsList, Operation, Warnings, Redoc, SecurityDefinitions,
LoadingBar, SideMenuItems, RedocSearch, ExternalDocs, EndpointLink
];
export { ApiInfo, ApiLogo, JsonSchema, JsonSchemaLazy, ParamsList, RequestSamples, ResponsesList,
-ResponsesSamples, SchemaSample, SideMenu, OperationsList, Operation, Warnings, Redoc, SecurityDefinitions,
+ResponsesSamples, AuthScopes, SchemaSample, SideMenu, OperationsList, Operation, Warnings, Redoc, SecurityDefinitions,
LoadingBar, SideMenuItems, ExternalDocs, EndpointLink };
diff --git a/lib/utils/spec-manager.ts b/lib/utils/spec-manager.ts
index 6a399da4..bce5d1d7 100644
--- a/lib/utils/spec-manager.ts
+++ b/lib/utils/spec-manager.ts
@@ -140,6 +140,41 @@ export class SpecManager {
return obj;
}
+ getOperationScopes(operationPtr:string) {
+ const getSecurityDefinition = (name: string, scope: string) => {
+ let secDefs = this._schema.securityDefinitions;
+ if (secDefs[name] && secDefs[name].type === 'oauth2') {
+ let availScopes = secDefs[name].scopes;
+ if (availScopes && availScopes[scope]) {
+ return availScopes[scope];
+ }
+ }
+ return null;
+ };
+
+ let securityParams = this.byPointer(operationPtr) || [];
+ let scopes = [];
+
+ // only support one security item per operation for now
+ let base = securityParams[0];
+
+ if (base && base[Object.keys(base)[0]]) {
+ let scopeObj = base[Object.keys(base)[0]];
+ let authName = Object.keys(base)[0];
+ Object.keys(scopeObj).forEach(key => {
+ let val = scopeObj[key];
+ let desc = getSecurityDefinition(authName, val);
+
+ // don't add if the security obj doesn't exist in the security definitions
+ if (desc) {
+ scopes.push({name: val, description: desc});
+ }
+ });
+ }
+
+ return scopes;
+ }
+
getOperationParams(operationPtr:string):SwaggerParameter[] {
/* inject JsonPointer into array elements */
function injectPointers(array:SwaggerParameter[], root) {
diff --git a/tests/schemas/schema-mgr-operation-security.json b/tests/schemas/schema-mgr-operation-security.json
new file mode 100644
index 00000000..ed9e613b
--- /dev/null
+++ b/tests/schemas/schema-mgr-operation-security.json
@@ -0,0 +1,108 @@
+{
+ "swagger": "2.0",
+ "info": {
+ "version": "1.0.0",
+ "title": "Test schema"
+ },
+ "host": "petstore.swagger.io",
+ "basePath": "/v2/",
+ "parameters": {
+ "extparam": {
+ "name": "extParam",
+ "in": "query",
+ "type": "integer"
+ }
+ },
+ "securityDefinitions": {
+ "petstore_auth": {
+ "type": "oauth2",
+ "authorizationUrl": "http://petstore.swagger.io/api/oauth/dialog",
+ "flow": "implicit",
+ "scopes": {
+ "write:pets": "modify pets in your account",
+ "read:pets": "read your pets"
+ }
+ },
+ "github_auth": {
+ "type": "oauth2",
+ "authorizationUrl": "https://api.github.com/authorize",
+ "flow": "implicit",
+ "scopes": {
+ "write:account": "modify your account",
+ "read:account": "read your account"
+ }
+ },
+ "api_key": {
+ "type": "apiKey",
+ "name": "api_key",
+ "in": "header"
+ }
+ },
+ "paths": {
+ "test1": {
+ "parameters": [
+ {
+ "name": "pathParam",
+ "in": "path",
+ "type": "string"
+ }
+ ],
+ "get": {
+ "summary": "test get",
+ "parameters": [
+ {
+ "name": "operationParam",
+ "in": "path",
+ "type": "string"
+ }
+ ],
+ "security": [
+ {
+ "petstore_auth": [
+ "write:pets",
+ "read:pets"
+ ]
+ }
+ ]
+ }
+ },
+ "test2": {
+ "parameters": [
+ { "$ref": "#/parameters/extparam" }
+ ],
+ "get": {
+ "summary": "test get",
+ "parameters": [
+ {
+ "name": "operationParam",
+ "in": "path",
+ "type": "string"
+ }
+ ]
+ }
+ },
+ "test3": {
+ "get": {
+ "summary": "test get",
+ "parameters": [
+ { "$ref": "#/parameters/extparam" }
+ ],
+ "security": [
+ {
+ "github_auth": [
+ "write:account"
+ ]
+ }
+ ]
+ }
+ },
+ "test4": {
+ "parameters": {
+ "$ref": "#/parameters/extparam"
+ },
+ "get": {
+ "summary": "test get"
+ }
+ }
+ }
+}
diff --git a/tests/unit/SpecManager.spec.ts b/tests/unit/SpecManager.spec.ts
index 5872c32e..c8841cb7 100644
--- a/tests/unit/SpecManager.spec.ts
+++ b/tests/unit/SpecManager.spec.ts
@@ -105,6 +105,33 @@ describe('Utils', () => {
});
});
+ describe('getOperationScopes method', () => {
+ beforeEach(function (done) {
+ specMgr.load('/tests/schemas/schema-mgr-operation-security.json').then(done, done.fail);
+ });
+
+ it('should handle operation oauth2 scopes', () => {
+ let scopes = specMgr.getOperationScopes('/paths/test1/get/security');
+ scopes.length.should.be.equal(2);
+ scopes[0].name.should.be.equal('write:pets');
+ scopes[0].description.should.be.equal('modify pets in your account');
+ scopes[1].name.should.be.equal('read:pets');
+ scopes[1].description.should.be.equal('read your pets');
+ });
+
+ it('should handle operation scopes when multiple definitions are used', () => {
+ let scopes = specMgr.getOperationScopes('/paths/test3/get/security');
+ scopes.length.should.be.equal(1);
+ scopes[0].name.should.be.equal('write:account');
+ scopes[0].description.should.be.equal('modify your account');\
+ });
+
+ it('should handle the case when no security is present', () => {
+ let scopes = specMgr.getOperationScopes('/paths/test2/get/security');
+ scopes.length.should.be.equal(0);
+ });
+ });
+
describe('getOperationParams method', () => {
beforeEach((done:any) => {
specMgr.load('/tests/schemas/schema-mgr-operationParams.json').then(done, done.fail);