I finally got my oauth2 server running.
From command line, if I run
curl -s -u acme:acmesecret -d grant_type=password -d username=myusername -d password=mypassword -H Accept:application/json http://localhost:9999/oauth/token
I got result below,
{
"access_token":"eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE0Mzk1NDU3ODAsInVzZXJfbmFtZSI6IisxIDQwODUxODIxMTUiLCJhdXRob3JpdGllcyI6WyJVU0VSIiwiQURNSU4iXSwianRpIjoiYmFkMDgyMjctNDExNC00OTZkLWE1NDMtYzBhMjc3YTBhZDkzIiwiY2xpZW50X2lkIjoiYWNtZSIsInNjb3BlIjpbIndlYnNob3AiXX0.CM_0gBHVyecOMmpc2cnKTus48PNv8gfHDyzVOVa5TBDxv4QlnDO93otmUs86IQqPaqaI133tT1NPU0pt2dbV5lrY3FOlPFXB0zZw5ptIXCtpaQLgl3e9hkB1aSfv3YxbHiOV8n3FcvNdz9Ihi9XEQdzqT8YfK7mCeMOjdb1i6Ve9axwjJI9ZHxXzDMcJsnYBcQCKG52G3-rWzgzlaQkPZY6mO7q0eO0jgVWthLfSBumHlDt9QXaBkETH3CRHxSuJqlo4J3TZxP4-1vPLkgh8Ku2rY5A9rT-xOKG8_5s2CJduCZt0qQrXZhz7sk0m2IdxDDwXumPv6zyHyD2J3sjHUA",
"token_type": "bearer",
"refresh_token": "eyJhbGciOiJSUzI1NiJ9.eyJ1c2VyX25hbWUiOiIrMSA0MDg1MTgyMTE1Iiwic2NvcGUiOlsid2Vic2hvcCJdLCJhdGkiOiJiYWQwODIyNy00MTE0LTQ5NmQtYTU0My1jMGEyNzdhMGFkOTMiLCJleHAiOjE0NDIwOTQ1ODAsImF1dGhvcml0aWVzIjpbIlVTRVIiLCJBRE1JTiJdLCJqdGkiOiJjYWNkOWEzOC1mOWE5LTQ4NjAtOWZmMi05NWMzMzU4MmY0NDAiLCJjbGllbnRfaWQiOiJhY21lIn0.DhaqIEdYWR2VPkgh72bQ17ZLqcVVfdYtT8DdKibjIcZUTNNjN_atdyKYKNEtdSyEES-ArHL0jCVXUg3EKiut_qtvn8oaLYEAxCNfztHyo_b-RZIxOgr71m82n66vSwRzxQnoKcGltxpZs-PK5p-gmbaEWK4EO63AkJpgN_IrIGV4eVQmidanz53rvq-CBiq-1FFb64OilesUxkSPOVkbb-q-mUmd8EG4khdbf44LD9VhyZwt8lOOi8NnksnnGhogiynU9p7tirAv6w_g8IO7uy06fWaLyn6rAgPga3CYgo9ggFIICWKn-QFipkHgiehq6y_1-xTGlgHnRKXcnPIZcg",
"expires_in": 34996,
"scope": "webshop",
"jti": "bad08227-4114-496d-a543-c0a277a0ad93"
}
With the token returned, I can get user information with a curl command. You can a lot of user information in the response.
curl http://localhost:9999/user -H "Authorization: Bearer eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE0Mzk1NDU3ODAsInVzZXJfbmFtZSI6IisxIDQwODUxODIxMTUiLCJhdXRob3JpdGllcyI6WyJVU0VSIiwiQURNSU4iXSwianRpIjoiYmFkMDgyMjctNDExNC00OTZkLWE1NDMtYzBhMjc3YTBhZDkzIiwiY2xpZW50X2lkIjoiYWNtZSIsInNjb3BlIjpbIndlYnNob3AiXX0.CM_0gBHVyecOMmpc2cnKTus48PNv8gfHDyzVOVa5TBDxv4QlnDO93otmUs86IQqPaqaI133tT1NPU0pt2dbV5lrY3FOlPFXB0zZw5ptIXCtpaQLgl3e9hkB1aSfv3YxbHiOV8n3FcvNdz9Ihi9XEQdzqT8YfK7mCeMOjdb1i6Ve9axwjJI9ZHxXzDMcJsnYBcQCKG52G3-rWzgzlaQkPZY6mO7q0eO0jgVWthLfSBumHlDt9QXaBkETH3CRHxSuJqlo4J3TZxP4-1vPLkgh8Ku2rY5A9rT-xOKG8_5s2CJduCZt0qQrXZhz7sk0m2IdxDDwXumPv6zyHyD2J3sjHUA"
{
"details": {
"remoteAddress": "127.0.0.1",
"sessionId": null,
"tokenValue": "eyJhbGciOiJSUzI1NiJ9.eyJleHAiOjE0Mzk1NDU3ODAsInVzZXJfbmFtZSI6IisxIDQwODUxODIxMTUiLCJhdXRob3JpdGllcyI6WyJVU0VSIiwiQURNSU4iXSwianRpIjoiYmFkMDgyMjctNDExNC00OTZkLWE1NDMtYzBhMjc3YTBhZDkzIiwiY2xpZW50X2lkIjoiYWNtZSIsInNjb3BlIjpbIndlYnNob3AiXX0.CM_0gBHVyecOMmpc2cnKTus48PNv8gfHDyzVOVa5TBDxv4QlnDO93otmUs86IQqPaqaI133tT1NPU0pt2dbV5lrY3FOlPFXB0zZw5ptIXCtpaQLgl3e9hkB1aSfv3YxbHiOV8n3FcvNdz9Ihi9XEQdzqT8YfK7mCeMOjdb1i6Ve9axwjJI9ZHxXzDMcJsnYBcQCKG52G3-rWzgzlaQkPZY6mO7q0eO0jgVWthLfSBumHlDt9QXaBkETH3CRHxSuJqlo4J3TZxP4-1vPLkgh8Ku2rY5A9rT-xOKG8_5s2CJduCZt0qQrXZhz7sk0m2IdxDDwXumPv6zyHyD2J3sjHUA",
"tokenType": "Bearer",
"decodedDetails": null
},
"authorities": [
{
"authority": "USER"
},
{
"authority": "ADMIN"
}
],
"authenticated": true,
"userAuthentication": {
"details": {
"grant_type": "password",
"username": "myusername"
},
"authorities": [
{
"authority": "USER"
},
{
"authority": "ADMIN"
}
],
"authenticated": true,
"principal": {
"id": "usr000d11b4c86-13ba-11e5-b905-56847afe9799",
"json": null,
"version": 0,
"created": 1434412879774,
"updated": 1438877901186,
"info": {
"nickName": "Kevin",
"country": "China",
"zipcode": null,
"state": null,
"city": "",
"occupation": "",
"gender": null,
"imgPath": "https://ddbs0erhouflt.cloudfront.net/mcf000ecd36bcb-f33e-4d50-9102-7a8706b45eb8",
"about": "",
"dueDate": 1447312895201,
"birthday": 0
},
"privateInfo": {
"email": "zyj#yahoo.com",
"phone": "myusername",
"password": "f45206ce4247b5d9af350d4600adc85c",
"tempPassword": null,
"tokens": null
},
"settings": null,
"type": "Super",
"status": "Active",
"enabled": true,
"username": "myusername",
"password": "f45206ce4247b5d9af350d4600adc85c",
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true,
"authorities": [
{
"authority": "USER"
},
{
"authority": "ADMIN"
}
]
},
"credentials": null,
"name": "myusername"
},
"credentials": "",
"oauth2Request": {
"clientId": "acme",
"scope": [
"webshop"
],
"requestParameters": {
"grant_type": "password",
"username": "myusername"
},
"resourceIds": [],
"authorities": [],
"approved": true,
"refresh": false,
"redirectUri": null,
"responseTypes": [],
"extensions": {},
"grantType": "password",
"refreshTokenRequest": null
},
"principal": {
"id": "usr000d11b4c86-13ba-11e5-b905-56847afe9799",
"json": null,
"version": 0,
"created": 1434412879774,
"updated": 1438877901186,
"info": {
"nickName": "Kevin",
"country": "China",
"zipcode": null,
"state": null,
"city": "",
"occupation": "",
"gender": null,
"imgPath": "https://ddbs0erhouflt.cloudfront.net/mcf000ecd36bcb-f33e-4d50-9102-7a8706b45eb8",
"about": "",
"dueDate": 1447312895201,
"birthday": 0
},
"privateInfo": {
"email": "zyj#yahoo.com",
"phone": "myusername",
"password": "f45206ce4247b5d9af350d4600adc85c",
"tempPassword": null,
"tokens": null
},
"settings": null,
"type": "Super",
"status": "Active",
"enabled": true,
"username": "myusername",
"password": "f45206ce4247b5d9af350d4600adc85c",
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true,
"authorities": [
{
"authority": "USER"
},
{
"authority": "ADMIN"
}
]
},
"clientOnly": false,
"name": "myusername"
}
I have a Spring boot micro service client. It uses spring-cloud-security. One of the web service was below,
#RequestMapping(value="getsth", method=RequestMethod.GET)
public SomeObject getsth(Principal principal) {
....
}
When method getsth is called, I can see an object of OAuth2Authentication was passed in. However, user information like user id, user phone number are missing.
My question: how can I get all the user information? Is there any way to custom the principal object?
Thanks,
I was struggling with the same issue. I got it to work however.
I'm using JWT so might be slightly different to what you're doing, but the concept is the same.
First of all, I created a custom TokenServices to get the extra information out of the user and added it to the authentication object:
public class TafTokenServices extends DefaultTokenServices {
#Override
public OAuth2AccessToken createAccessToken(OAuth2Authentication authentication) throws AuthenticationException {
final TafUserDetails tafUserDetails = (TafUserDetails)authentication.getPrincipal();
final Map<String, Object> tafInfo = new HashMap<>();
tafInfo.put("EMAIL", tafUserDetails.getEmailAddress());
authentication.setDetails(tafInfo);
return super.createAccessToken(authentication);
}
}
Then configure your auth server to use it:
#Configuration
#EnableAuthorizationServer
protected static class OAuth2Config extends AuthorizationServerConfigurerAdapter {
#Autowired
private AuthenticationManager authenticationManager;
#Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
endpoints.authenticationManager(authenticationManager).accessTokenConverter(jwtAccessTokenConverter())
.tokenServices(tafTokenServices());
}
#Bean
public AuthorizationServerTokenServices tafTokenServices() {
final TafTokenServices tafTokenServices = new TafTokenServices();
final JwtTokenStore jwtTokenStore = new JwtTokenStore(this.jwtAccessTokenConverter());
tafTokenServices.setTokenStore(jwtTokenStore);
tafTokenServices.setTokenEnhancer(this.jwtAccessTokenConverter());
return tafTokenServices;
}
Also in the auth server you need to then transfer the data out of the authentication object into the token with your own AccessTokenCoverter object:
public class TafJwtAccessTokenConverter extends JwtAccessTokenConverter {
private static final String EMAIL_KEY = "EMAIL";
#Override
public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
final Map<String, Object> authDetails = (Map<String, Object>)authentication.getDetails();
((DefaultOAuth2AccessToken)accessToken).setAdditionalInformation(authDetails);
return super.enhance(accessToken, authentication);
}
#Override
public OAuth2Authentication extractAuthentication(Map<String, ?> map) {
final OAuth2Authentication authentication = super.extractAuthentication(map);
final Map<String, String> details = new HashMap<>();
details.put(EMAIL_KEY, (String)map.get(EMAIL_KEY));
authentication.setDetails(details);
return authentication;
}
}
NOTE: the enhance() method is called during creation of the token, so you need this in the auth server.
NOTE: extractAuthentication() is called in the downstream services during authentication, so this implementation needs to exist there as well. You need to configure your resource server to use this AccessTokenConverter.
That will get the info into the token to pass downstream. Note I didn't want to keep the data in the custom user object because I don't want to have my other services depend on that object.
The next step is to get the stuff out of the token and use it in your resource server. You do this by overriding extractAuthentication() to get the details from the map and put them into the authentication object. They will now be available in your application by doing something like this:
private String getEmail() {
final OAuth2Authentication auth = this.getAuthentication();
final OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails)auth.getDetails();
final Map<String, Object> map = (Map)details.getDecodedDetails();
return "Your email address is " + map.get("EMAIL");
}
private OAuth2Authentication getAuthentication() {
return (OAuth2Authentication)SecurityContextHolder.getContext().getAuthentication();
}
I'm not sure this is right way to go, it's a bit fiddly. I have an issue open here where there is a discussion about it:
https://github.com/spring-cloud/spring-cloud-security/issues/85#issuecomment-165498497
to customize it you have to provide your own UserDetailsService class:
#Service
public class MyUserDetailsService implements UserDetailsService {
#Autowired
private UserRepository userRepository;
#Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
return userRepository.findByUsername(username);
}
}
where User is your entity with all fields you require:
public class User implements Serializable, UserDetails {...
then you have to configure spring security to actually use your custom user details service. Something similar to:
#Configuration
#EnableWebMvcSecurity
#EnableGlobalAuthentication
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private MyUserDetailsService myUserDetailsService;
#Autowired
private AuthenticationManager authenticationManager;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth
.parentAuthenticationManager(authenticationManager)
.userDetailsService(myUserDetailsService);
}
Related
I am having a problem getting data in android from atlas mongoDB (stitch):
service not found: 'mongodb-atlas'
StitchError: service not found: 'mongodb-atlas'
{
"arguments": [
{
"database": "vutuduDB",
"collection": "test",
"query": {},
"limit": {
"$numberInt": "0"
},
"project": null,
"sort": null
}
],
"name": "find",
"service": "mongodb-atlas"
}
Also when I tried to create a http service and use the console I got the same problem while running the line:
context.services.get("mongodb-atlas");
Java code:
public class SearchFragment extends Fragment {
Button btnSearch;
private StitchAppClient stitchClient;
private RemoteMongoClient mongoClient;
private RemoteMongoCollection itemsCollection;
#Override
public View onCreateView(#NonNull LayoutInflater inflater, #Nullable ViewGroup container,
#Nullable Bundle savedInstanceState) {
super.onCreateView(inflater, container, savedInstanceState);
View layout = inflater.inflate(R.layout.search_fragment_layout, container, false);
this.stitchClient = Stitch.getDefaultAppClient();
Log.d("stitch", "logging in anonymously");
stitchClient.getAuth().loginWithCredential(new AnonymousCredential()
).continueWithTask(new Continuation<StitchUser, Task<Void>>() {
#Override
public Task<Void> then(#NonNull Task<StitchUser> task) throws Exception {
if (task.isSuccessful()) {
Log.d("stitch", "logged in anonymously as user " + task.getResult());
} else {
Log.e("stitch", "failed to log in anonymously", task.getException());
}
mongoClient = stitchClient.getServiceClient(RemoteMongoClient.factory, "mongodb-atlas");
RemoteMongoDatabase db = mongoClient.getDatabase("vutuduDB");
Log.d("stitch", "GETTING ITEMS");
db.getCollection("test").find().forEach(item -> Log.d("ITEM: ", item.toString()));
return null;
}
});
return layout;
}
}
I have a simple POST request sending params using application/x-www-form-urlencoded encoding.
Looking in the wiremock docs I can't find a way to match the request by the params values, something like the querystring match I mean.
Furthermore it seems also impossible to contains for the body, nor to match the entire body in clear (just as base64).
Is there a way to match this kind of requests?
Another option that I found was to use contains for Stubbing Content-Type: application/x-www-form-urlencoded
{
"request": {
"method": "POST",
"url": "/oauth/token",
"basicAuthCredentials": {
...
},
"bodyPatterns": [
{
"contains": "username=someuser"
}
]
},
"response": {
....
}
}
With classic wiremock you can use bodyPatterns' matchers and regular expressions:
for example:
...
"request": {
"method": "POST",
"url": "/api/v1/auth/login",
"bodyPatterns": [
{
"matches": "(.*&|^)username=test($|&.*)"
},
{
"matches": "(.*&|^)password=123($|&.*)"
}
]
},
I had a similar problem - I wanted to check the exact parameters , but without patterm magic (so easier to maintain). As a workaround, I created a helper class :
import java.util.Iterator;
import java.util.LinkedHashMap;
public class WireMockUtil {
public static String toFormUrlEncoded(LinkedHashMap<String, String> map) {
if (map == null) {
return "";
}
StringBuilder sb = new StringBuilder();
Iterator<String> it = map.keySet().iterator();
while (it.hasNext()) {
String key = it.next();
String value = map.get(key);
appendFormUrlEncoded(key,value,sb);
if (it.hasNext()) {
sb.append('&');
}
}
return sb.toString();
}
public static String toFormUrlEncoded(String key, String value) {
StringBuilder sb = new StringBuilder();
appendFormUrlEncoded(key, value,sb);
return sb.toString();
}
public static void appendFormUrlEncoded(String key, String value, StringBuilder sb) {
sb.append(key).append('=');
if (value != null) {
sb.append(value);
}
}
}
Inside the Wiremock test you can use it via:
LinkedHashMap<String, String> map = new LinkedHashMap<>();
map.put("key1", "value1");
map.put("key2", "value2");
...
withRequestBody(equalTo(WireMockUtil.toFormUrlEncoded(map))).
Or check only dedicated parts by containing:
withRequestBody(containing(WireMockUtil.toFormUrlEncoded("key","value1"))).
You could try https://github.com/WireMock-Net/WireMock.Net
Matching query parameters and body can be done with this example json:
{
"Guid": "dae02a0d-8a33-46ed-aab0-afbecc8643e3",
"Request": {
"Url": "/testabc",
"Methods": [
"put"
],
"Params": [
{
"Name": "start",
"Values": [ "1000", "1001" ]
},
{
"Name": "end",
"Values": [ "42" ]
}
],
"Body": {
"Matcher": {
"Name": "WildcardMatcher",
"Pattern": "test*test"
}
}
}
}
How do I map roles in my resource server?
I have created what I believe to be the most simple implementation of a resource server in Spring Boot:
Application.java
#SpringBootApplication
#RestController
#EnableResourceServer
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#RequestMapping(value = "/user")
public Principal user(Principal principal) {
return principal;
}
}
application.properties
security.oauth2.resource.user-info-uri=myUserInfoUri
security.oauth2.client.client-id=myId
security.oauth2.client.client-secret=mySecret
pom.xml
...
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
</dependencies>
The app works well. I make a call to my auth server (in this case KeyCloak) and retrieve a token. I then do a http get to http://localhost:8080/user/ with the token passed in as the Authorization header.
The HTTP response contains information from the token however the authorities property is set to ROLE_USER. This does not match the roles in the token.
HTTP response
...
"userAuthentication": {
"authorities": [
{
"authority": "ROLE_USER"
}
],
"details": {
"sub": "93f566bd-df68-4c68-b3c6-0173c476bc02",
"name": "Andrew Neeson",
"preferred_username": "andy",
"given_name": "Andrew",
"family_name": "Neeson",
...
Token (parsed)
...
"realm_access": {
"roles": [
"role_1",
"role_2"
]
},
"resource_access": {
"account": {
"roles": [
"manage-account",
"view-profile"
]
}
},
"name": "Andrew Neeson",
"preferred_username": "andy",
"given_name": "Andrew",
"family_name": "Neeson",
...
How do I extract the desired information from the token?
I've resolved by creating a token mapper in keycloak client.
In my case the mapper has these parameters:
name: authorities
mapper type: User Realm Role
Token Claim Name: authorities
Add to access token: on
Add to userinfo: on
I hope this can help!
Giampiero.
I would like to secure my endpoint so only users with the role READ can access a certain resource. Those are my configurations:
Controller:
#RestController
#RequestMapping("/api/status")
public class StatusController {
#RequestMapping(method = RequestMethod.GET)
#Secured("READ")
Map<String, Object> getSecureStatus() {
Map<String, Object> statusMap = new LinkedHashMap<>();
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
statusMap.put("auth", auth);
return statusMap;
}
}
The WebSecurityConfigurerAdapter:
#Configuration
#EnableGlobalMethodSecurity(securedEnabled = true)
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
// .antMatchers("/").permitAll()
.antMatchers("/api/**").authenticated()
.and()
.httpBasic();
}
}
GlobalAuthenticationConfigurerAdapter:
#Configuration
public class AuthenticationManagerConfig extends
GlobalAuthenticationConfigurerAdapter {
#Override
public void init(AuthenticationManagerBuilder auth) throws Exception {
auth.inMemoryAuthentication()
.withUser("teddy").password("password").roles("USER");
}
}
I would assume that Teddy shouldn't be able to access the resource, as his role is USER rather than READ.
But with this call, Teddy gets his information anyway:
curl -u teddy:password 'http://localhost:8080/api/status/':
{
"auth": {
"details": {
"remoteAddress": "127.0.0.1",
"sessionId": null
},
"authorities": [
{
"authority": "ROLE_USER"
}
],
"authenticated": true,
"principal": {
"password": null,
"username": "teddy",
"authorities": [
{
"authority": "ROLE_USER"
}
],
"accountNonExpired": true,
"accountNonLocked": true,
"credentialsNonExpired": true,
"enabled": true
},
"credentials": null,
"name": "teddy"
}
}
What am I missing?
Edit: removed .antMatchers("/").permitAll()
Probably it's because you're using .antMatchers("/").permitAll() it's telling spring that you're allowing every request.
Try removing it from your configuration.
I found the mistake. I overlooked that getSecureStatus() wasn't explicitely defined public. This code fixes it:
#RestController
#RequestMapping("/api/status")
public class StatusController {
#RequestMapping(method = RequestMethod.GET)
#Secured("READ")
public Map<String, Object> getSecureStatus() {
Map<String, Object> statusMap = new LinkedHashMap<>();
Authentication auth = SecurityContextHolder.getContext().getAuthentication();
statusMap.put("auth", auth);
return statusMap;
}
}
I have tried a lot of things but APIs are not getting detected by swagger for some reason. Do i have to specify a package for swagger to scan? or some url include patterns?
My Swager Config :
#Configuration
#EnableSwagger
#EnableWebMvc
public class SwaggerConfiguration {
private final Logger log = LoggerFactory
.getLogger(SwaggerConfiguration.class);
/**
* Swagger Spring MVC configuration.
*/
#Bean
public SwaggerSpringMvcPlugin swaggerSpringMvcPlugin(
SpringSwaggerConfig springSwaggerConfig) {
log.debug("Starting Swagger");
StopWatch watch = new StopWatch();
watch.start();
SwaggerSpringMvcPlugin swaggerSpringMvcPlugin = new SwaggerSpringMvcPlugin(
springSwaggerConfig).apiInfo(apiInfo())
.genericModelSubstitutes(ResponseEntity.class);
swaggerSpringMvcPlugin.build();
watch.stop();
log.debug("Started Swagger in {} ms", watch.getTotalTimeMillis());
return swaggerSpringMvcPlugin;
}
/**
* API Info as it appears on the swagger-ui page.
*/
private ApiInfo apiInfo() {
return new ApiInfo("Title", "Description", "terms of service",
"contact", "license", "licenseUrl");
}
}
Sample Controller
#RequestMapping("/settings")
#Controller
#Api(value = "/settings", description = "Endpoint for settings management")
public class SettingsController {
#ApiOperation(value = "API Operation")
#RequestMapping(value = "/changepassword", method = RequestMethod.POST)
public #ResponseBody Map<String, Object> changePassword(#RequestParam Map<String, String> userProperties,
Model model, HttpServletRequest httpServletRequest, Locale locale) {
Map<String, Object> responseMap = new HashMap<String, Object>();
return responseMap;
}
}
I get an empty response
{
"apiVersion": "1.0",
"swaggerVersion": "1.2",
"apis": [ ],
"authorizations": [ ],
"info":
{
"title": "Title",
"description": "Description",
"termsOfServiceUrl": "terms of service",
"contact": "contact",
"license": "license",
"licenseUrl": "licenseUrl"
}
}
I am using swagger-springmvc version 1.0.2 and spring version 4.1.6.RELEASE
Follow the instructions in the following URL :
http://naddame.blogspot.in/2014/12/spring-roo-mvc-integration-for-swagger.html